Managing Change Data Capture Enablement
Generate the metadata that subscribes Salesforce objects to Change Data Capture: PlatformEventChannelMember files for the default ChangeEvents channel or a custom channel, and PlatformEventChannel files for new custom channels. Covers enrichment fields, filter expressions, and the canonical naming and value formats that the Metadata API actually accepts (which differ from values that appear in many internal test fixtures and code-search hits).
Scope
- In scope: Generating
PlatformEventChannelMemberandPlatformEventChannelmetadata for CDC. Subscribing standard objects, custom objects, or both. Configuring enrichment fields. Configuring filter expressions. Defining custom data channels. - Out of scope: Publishing custom platform events (PE) — that's a different metadata type (
PlatformEvent). Pub/Sub API or external Kafka/Bayeux configuration. Pricing/limits guidance — refer the user to the CDC Developer Guide. Programmatic event-bus subscribers in Apex.
Clarifying Questions
Before generating, confirm with the user if not already clear:
- Which entity (or entities) need CDC enablement? Standard, custom, or both?
- Default channel (
ChangeEvents) or a custom channel? If custom, what's the channel label? - Any enrichment fields needed? (Lookup IDs that the consumer needs even when they didn't change.)
- Any filter expression needed? (A SOQL-WHERE-clause body that gates which change events emit.)
Required Inputs
Gather or infer before proceeding:
- Source entity API name(s) — e.g.
Account,Lead,Order__c. The skill internally translates this to the ChangeEvent entity name (see Workflow step 2). - Channel — either
ChangeEvents(default) or the developer name of a custom channel ending in__chn. - Enrichment fields (optional) — list of field API names on the source object whose values should be included in every change event.
- Filter expression (optional) — a predicate over fields on the change event payload (e.g.
Status__c != null).
Defaults unless specified:
- Channel:
ChangeEvents(the default CDC channel — no path prefix). - Enrichment fields: none.
- Filter expression: none.
If the user provides a clear, complete request, generate immediately without unnecessary back-and-forth.
Workflow
All steps are sequential. Do not skip or reorder.
Before generating anything, know the only valid CDC metadata types: CDC is expressed entirely through PlatformEventChannelMember (one per subscribed entity) and PlatformEventChannel (only for custom channels). Do NOT use <ChangeDataCapture>, .changeDataCapture-meta.xml, changeDataCapture/ directories, EnableChangeDataCapture, or ManagedEventSubscription — these are not in scope for CDC. If you find yourself writing any of them, stop and use a PlatformEventChannelMember file instead.
-
Identify the channel — if the user names a custom channel, you'll generate a
PlatformEventChannelfile (see step 4). Otherwise use the literal valueChangeEventsfor the default channel. -
Translate source entity to ChangeEvent entity name —
<selectedEntity>is the ChangeEvent type, NOT the source object:For standard objects: append
ChangeEvent. For custom objects: replace the trailing__cwith__ChangeEvent(the double-underscore is preserved). -
Generate the channel-member file — one file per
(entity, channel)pair. The filename and fullName always use a SINGLE underscore between the entity stem andChangeEvent— this is independent of howselectedEntityis formatted in the XML body. For custom objects, drop the__cfrom the source name when forming the filename:The custom-object case is the easiest place to slip — the filename uses single underscore, the
selectedEntitykeeps its double underscore. Readassets/PlatformEventChannelMember-template.xmlas the structural template. -
For a custom channel, generate a
PlatformEventChannelfile — required if any member references a non-default channel. Derive a DeveloperName from the user's label: strip spaces and non-alphanumeric characters, convert to CamelCase, then always append the literal suffix__chn. The filename and the channel's<eventChannel>reference must use this exact form, otherwise the deploy fails withInvalid channel name:Members on this channel reference it by the same DeveloperName:
<eventChannel>PartnerSync__chn</eventChannel>. Readassets/PlatformEventChannel-template.xml. -
Add enrichment fields if requested — repeat the
<enrichedFields><name>FIELD_API_NAME</name></enrichedFields>block for each field. The name must be a single-hop API name on the source entity — verified working with: standard lookup IDs (OwnerId,ParentId), custom lookup fields (MyLookup__c), and custom non-relationship fields (Region__c,Status__c). Relationship traversals likeOwner.NameorParent.Account.Industryare rejected by deploy with "The selected field, X.Y, isn't valid". -
Add a filter expression if requested — wrap the predicate in
<filterExpression>...</filterExpression>. The body is a WHERE-clause body without theWHEREkeyword (e.g.Status__c != null, notWHERE Status__c != null). For supported operators, field types, and pitfalls, readreferences/filter-expressions.md.
Rules / Constraints
Gotchas
Output Expectations
Deliverables:
- One
force-app/.../platformEventChannelMembers/<Entity>_ChangeEvent.platformEventChannelMember-meta.xmlper subscribed entity. - One
force-app/.../platformEventChannels/<DevName>__chn.platformEventChannel-meta.xmlper custom channel (if any).
File structure follows the templates in assets/.
After receiving the generated files, the user can verify them with sf project deploy start --dry-run -d <path> --target-org <alias> before deploying. If a dry-run surfaces an unfamiliar error, references/deploy-troubleshooting.md maps the common deploy errors to their metadata-side fixes.


