Consents in Marketing Cloud Next look easy. Communication Subscriptions, split by channel, attached to a Contact Point Value instead of a person. But once you get to correct setup, scale, double opt-ins and synchronization, this topic becomes complex fast.
And there is one more thing nobody tells you up front. At send time the platform doesnβt read the record you just wrote, but it reads a cache, and that cache can be three months old. Salesforce also has a complete platform-level consent model that Marketing Cloud Next mostly ignores, which matters the first time you find an object that looks like it solves your problem.
How Consent Works in Marketing Cloud Next
As in every other marketing platform, consent in Marketing Cloud Next governs the verification of permissions required to deliver a message. Without proper consent the system blocks the send before it goes out. And as in every other platform, it comes with catches and a specific schema that you are better off understanding before you build against it.
Three rules explain almost everything else in this article:
- Consent attaches to a contact point value, not to a person.
- No consent record means opted out.
- At send time, the source of truth is a cache, not the record.
Consent Attaches to Contact Points
Time for the first rule of MC Next Club. Consent attaches directly to a Contact Point Value β an email address, or a phone number in E.164 format. One value, one communication subscription, one channel. These records live in Data 360, in the Communication Subscription Consent DMO. A communication subscription is a named thing people can subscribe to β Weekly Newsletter, Order Updates, Price Alerts. A DMO is the object in Data 360 that stores the records.
Consent is not attached to an Individual, a Unified Individual (the single profile identity resolution builds by merging duplicates), or a CRM Prospect, Lead or Contact. It is also not duplicated anywhere in CRM. You will find a CommSubscriptionConsent object sitting in your org, and it will be empty.
Why this way? Letβs take a hypothetical. office@acme.com sits on two Contacts β the office manager, and the owner who shares the mailbox. Key consent on the person and the platform has to decide whose preference wins every time that address comes up in a send. Salesforceβs answer is not to decide at all. Key on the address, and treat an opt-out on it as binding for everyone behind it. The same logic gives you the more restrictive default, which is how regulators look at it anyway β they care about the address you wrote to, not the record you wrote it from.
So, where several individuals share a contact point, an opt-out applies to all of them, and there is no supported way to send to one and suppress the other. Whatβs more:
- Changing someoneβs email address strands their consent on the old address. The new one has no record, which means opted out.
- Deleting the Contact leaves the consent record in Data 360, keyed to an address that no longer appears anywhere in your CRM.
- Two people, one mailbox, one consent state. Even if they want different things.
No Record Means Opted Out
The second rule of MC Next Club is just as important. Every prospect, lead, contact and any other Individual is treated as opted out by default. No consent record for a contact point and subscription means opt-out.
This is a different approach from what weβve seen in Marketing Cloud Engagement and Pardot. Looks logical and enhances privacy, but means additional work to do. On the day you switch Marketing Cloud Next on, your entire existing database is opted out.
For commercial sends there is no supported path that drives sending from custom flag fields on Contact or Lead. They can feed the standard model through a flow, but they cannot replace it. Updating those objects on their own does nothing at send time. The same goes for consent data already sitting on the core CRM object, which has to reach the Data 360 DMO through a supported method before it counts for anything.
Thatβs why consent import is one of the first things you do after creating your communication subscriptions, and it deserves planning rather than an afternoon.
Bulk CSV, up to 50,000 rows per file, and each file covers exactly one channel, one subscription and one status. Two subscriptions across email and SMS, with both opt-in and opt-out, is eight combinations, so eight files before volume enters the picture. Then add 200,000 profiles and the 50,000-row limit splits several of those files again.
A sync flow handles consent changes going forward. It does nothing at all about the base you already have. These are two separate pieces of work, and the boring one is the one with the legal exposure.
One detail from the import sets the tone for everything below. Supply a consent date earlier than the one already on the record, and the platform ignores it. The row still imports. Nothing fails, nothing warns you, and the date you think you loaded is not the date thatβs there.
The record has two values, opt-in and opt-out, with nothing in between β which is the more irritating for knowing that the CRM CommSubscriptionConsent object, the empty one, carries OptInPending and OptOutPending since API version 58.0. Every state a double opt-in flow could want, on the object that has no bearing on whether an email goes out.
Send Time Reads a Cache
Before the third rule, a look at what actually gets checked. A consent check requires you to pick a communication subscription when you send, then verifies every recipient is opted in before the message goes out. Where it applies is not uniform:
| Message type | Consent check |
|---|---|
| Promotional email | Required |
| Transactional email | Not Required |
| Promotional SMS, WhatsApp, RCS | Required |
| Transactional SMS, WhatsApp, RCS | Required |
Marketing admins edit these under Setup, in the email channel settings, where promotional and transactional messages have separate switches. You can also turn consent checks off entirely if consent is managed on another platform, which Salesforce gates behind an explicit affirmation that you accept responsibility for whatever compliance problems follow. The same dialog adds something easy to miss: the change doesnβt affect active flows. Anything already running keeps checking.
SMS, WhatsApp and RCS work at a different granularity from email, and it surprises people. Each SMS code, WhatsApp number and RCS agent maps to one or more subscriptions, and opting out of the channel opts the person out of every subscription mapped to it. There is no per-subscription opt-out over SMS in the way there is over a preference page. RCS gets the one exception to the one-channel-one-consent rule, Salesforce says you can reuse existing SMS consent when the messaging use case stays the same, and tells you to check that with your legal team rather than assuming it.
Two addresses sit outside all of this. Compliance BCC copies every outgoing email to one designated address, and because that address doesnβt represent a person, Salesforce excludes it from consent checks entirely. CC recipients go the other way β if the primary recipient doesnβt get the email because the address lacks consent, the CC recipients donβt get it either.
Now the third rule of MC Next Club. At send time, the source of truth is a cache. Not the DMO.
The platform checks the cache for the recipientβs address, uses the cached value if one is there, and only queries the consent data when nothing is found, storing the result afterwards. A cached value can persist for up to 90 days unless something refreshes it.
In defence of the design: a per-recipient DMO query across a 400,000-recipient send would be brutal on latency and cost, and consent for any given address changes rarely. Caching it is the obvious call. The problem is that you cannot see the cache, cannot flush it, and cannot tell from any interface whether the value the send engine holds matches the value youβre looking at.
So βthe DMO says opted outβ tells you considerably less than youβd expect about whether the email goes out.
Consent Data Model in Marketing Cloud Next
Three rules down. Now the objects that implement them, and the two other consent models youβll trip over on the way.
Three Consent Models in Salesforce
Salesforce has more than one consent model, and a single org can contain all of them.
| Model | Question it answers |
|---|---|
| Salesforce Consent Data Model (Individual, ContactPointTypeConsent, ContactPointConsent, DataUsePurpose, with BusinessBrand alongside) | What is the legal basis for processing this personβs data? |
| Data 360 consent objects (Contact Point Consent, Privacy Consent Log) | Can this contact point be used in an activation? |
| Communication Subscription Consent | Can Marketing Cloud Next send this specific message? |
The first is Salesforceβs documented standard model, layered from global preferences on the Individual object down through channel type, contact point and purpose of use. It considers the whole person, and itβs what you want if your requirement is proof of consent or legal basis for an audit.
Marketing Cloud Next reads only the third one, through the cache. A perfectly maintained ContactPointTypeConsent record has no bearing whatsoever on whether an email goes out. Everything below this point is about that third model.
Four Consent Objects
| Object | Id prefix | What it is |
|---|---|---|
| Communication Subscription | 0Xl | the subscription (βWeekly Newsletterβ) |
| Engagement Channel Type | 0eF* | the channel (Email, SMS, WhatsApp, RCS) |
| Communication Subscription Channel Type | 0eB* | one subscription paired with one channel |
| Communication Subscription Consent | β | the consent record itself |
The first three are CRM objects. Standard Salesforce sObjects, available in all editions. CommSubscription and CommSubscriptionConsent have both been in the API since version 48.0, which is Spring β20, roughly five years before Marketing Cloud Next existed. When you create a subscription in the Consent tab, you create a CRM record. You can see them:
SELECT Id, Name FROM CommSubscription
SELECT Id, Name, CommSubscriptionId, EngagementChannelTypeId
FROM CommSubscriptionChannelType
The fourth object is the one that isnβt in CRM. Consent records live in Data 360 only. So βconsent is all in Data 360β and βthese are CRM objectsβ are both correct statements, about different halves of the same model. Worth knowing before you plan any reporting: Engagement Channel Type has no DMO at all. Communication Subscription Channel Type carries an ssot__EngagementChannelTypeId__c with no relationship attached, so on the Data 360 side the channel is a bare identifier pointing nowhere.
Three things about subscriptions that are much easier to get right at the start than to fix later:
- Scope cannot be changed. With business units enabled (Advanced Edition), a subscription is assigned either to a single business unit or to all of them, and the scope cannot be edited after creation. The assignment also limits which channels you can add to it.
- Deleting a subscription deletes all of its consent data. Thatβs a legal exposure rather than an admin inconvenience, and Salesforceβs own recommendation is simply not to delete subscriptions once consent has been collected against them.
- A new subscription does not appear on your preference page. Marketing Cloud Next ships one customizable email preference page, and by default it contains the default marketing communication subscription and nothing else. You decide which subscriptions appear on it, and adding them is a separate step after you create the subscription.
- There is no frequency capping on a subscription. The platform has a
CommSubscriptionTimingobject for exactly this, related to consent in Salesforceβs own model. Marketing Cloud Next doesnβt map it. If you need send-frequency rules, they live in your journey logic or segment.
How the Objects Connect
A consent record keys on the contact point value combined with the Communication Subscription Channel Type Id. That pairing is the whole join key, and it explains both whatβs easy and whatβs impossible: searching consent by email address works, searching it by person doesnβt. The Relationships tab confirms it from the other side: the consent DMO has exactly one relationship you can traverse, N:1 to Communication Subscription Channel Type. Nothing to Contact Point Email. The link to a person isnβt a weak relationship here, itβs a string comparison you make yourself.
There is also an out of the box relationship between Individual.Id and CommunicationSubscriptionConsent.Party. There will be no records connected through it.
The field is not a leftover and itβs not broken. The DMO is a standard object in the Data 360 Privacy subject area, designed for consent arriving from external systems that carry a person identifier. Marketing Cloud Next doesnβt use that path. Consent arrives in Data 360 through a data lake object, a raw landing table that is then mapped onto the DMO. I checked the data stream mapping in my own org (screenshot further down, in the data streams section) and ssot__PartyId__c is wired end to end from the data lake object to the DMO. Nothing ever flows through it. Salesforce confirms the same behaviour for the audit trail, describing PartyId as written blank by design even when the source record is a Lead or Contact.
The proper way β the same one the Privacy Consent Status component uses on Contact, Lead and Prospect β is to tie Communication Subscription Consent to the Individual through the Contact Point Email or Contact Point Phone DMO. Those carry the PartyId mapping that the consent record doesnβt.
Run this in the Data 360 Query Editor:
SELECT
c."ssot__ContactPointValueText__c" AS contact_point,
c."ssot__ConsentStatus__c" AS status,
cpe."ssot__PartyId__c" AS individual_id
FROM "ssot__CommunicationSubscriptionConsent__dlm" c
JOIN "ssot__ContactPointEmail__dlm" cpe
ON c."ssot__ContactPointValueText__c" = cpe."ssot__EmailAddress__c"
WHERE c."ssot__ContactPointValueText__c" = 'someone@example.com'
For phone consent, swap ContactPointEmail for ContactPointPhone and ssot__EmailAddress__c for ssot__FormattedE164PhoneNumber__c.
That namespace split is worth knowing about on its own. If you open the public DMO reference for ssot__CommunicationSubscriptionConsent__dlm, you wonβt find a contact point value field at all β it lists ssot__ContactPointId__c, a reference. The field you actually see in Data Explorer, labelled Contact Point Value, comes from the newer generation of the object. Two versions of the same DMO, documented in two places, and the documentation page most search engines rank first describes the one youβre probably not using.
Consent Data Streams
Consent records donβt appear in the DMO by magic, and the route they take explains most of the behaviour above.
Every supported write goes through Marketing Cloud Nextβs own consent service. The service writes into a data lake object, and that DLO is mapped to the Communication Subscription Consent DMO. The service is also what updates the cache, which is why the route matters more than the result.
The data kit that carries all of this is called UnifiedMessagingConsent, and it installs two data streams: one for the consent records themselves and one for the audit trail.
Two Data Stream Generations
Look at the Data 360 objects associated with Marketing Cloud Next and you may find more consent streams than you went looking for. There are two ways to end up with them, and only one of them is the one the documentation prepares you for.
The documented one is a generation switch. Orgs created before Summer β25 moved from MessagingConsent to MessagingConsentV2, and they can still hold two records for the same contact point and the same subscription, one written by each generation. If your org is newer than that, this is the paragraph you get to skip.
The one that catches everyone else has nothing to do with generations. Salesforce started appending the org ID to the stream names, both spellings stayed active, and an org that has only ever run V2 ends up with the same duplicate rows. That is the case in my own org, and the next section is where it gets pulled apart.
The send-time behaviour is fine, because the latest record wins. Your queries are not fine, because a naive SELECT against the DMO returns both rows and you have no obvious signal telling you which one the platform acted on. If you have ever pulled a consent export and found duplicate rows that you couldnβt explain, this is why.
Finding them, with the dangerous ones on top:
SELECT
"ssot__ContactPointValueText__c" AS contact_point,
"ssot__CommunicationSubscriptionChannelTypeId__c" AS channel_type,
COUNT(*) AS rows_found,
COUNT(DISTINCT "ssot__ConsentStatus__c") AS distinct_statuses
FROM "ssot__CommunicationSubscriptionConsent__dlm"
GROUP BY 1, 2
HAVING COUNT(*) > 1
ORDER BY distinct_statuses DESC
Sorting on distinct_statuses surfaces the contact points where the two streams disagree β same address, same subscription, one row opt-in and one opt-out.
Org ID in Stream Names
Salesforce started naming the V2 data streams with the org ID appended, so what you actually see in your org is closer to this:
MessagingConsentV2_00DXX00000XXXXX-MessagingConsent
ConsentAuditTrailV2_00DXX00000XXXXX-ConsentAuditTrail
Here is what that looks like in my org, with the record counts that say which stream is doing the work:
| Data stream | Records |
|---|---|
MessagingConsentV2-MessagingConsent | 8 |
MessagingConsentV2_<orgId>-MessagingConsent | 340 |
ConsentAuditTrailV2-ConsentAuditTrail | 12 |
ConsentAuditTrailV2_<orgId>-ConsentAuditTrail | 585 |
Both consent streams are V2, both are active, and they differ only in whether the org ID is in the name. So this isnβt a migration artefact you can dismiss as legacy β itβs the live state of an org that has only ever run V2. The larger stream does the current work, the smaller one is the tail, and both feed the same DMO.
The documentation acknowledges this in exactly one place: a note in the table of Data 360 objects associated with Marketing Cloud Next, saying that some DLOs are appended with the org ID or other identifying information.
The consequence is larger than the note suggests. Nothing that references the consent data lake object by name is portable. Not a Data Transform, not a saved query, not a Calculated Insight definition, not the runbook you wrote for your own team, and not anything you copy from a blog post β including this one, because the string above is masked and yours is different. It also means the name changes when the org ID changes, which is the same sandbox problem the subscription Ids have, arriving from a second direction.
Field Mapping
Hereβs the V2 data stream mapped to the DMO in my org:
Marketing Cloud Next populates a minority of the object it writes to, which is what youβd expect from a standard Data 360 object being used by one specific product.
ConsentIdis the primary key. Built from the contact point value combined with the Communication Subscription Channel Type Id, exactly as described above.ConsentCapturedDateTimeandUpdatedTimeare separate, mapping to Consent Captured Date Time and Last Modified Date. One tells you when the person decided, the other when the row last changed. They are frequently different, and only one of them is the date your legal team cares about.PartyIdis mapped toParty. Wired, connected, and carrying nothing.
How to Update Consent
One rule governs this whole section: only writes that go through the consent service count. Everything else produces a row and changes nothing in the consent cache.
Supported Methods
| Method | Use case |
|---|---|
| Bulk CSV import, 50,000 rows per file | Migration, one-time loads |
| Privacy Consent Status component | Manual, per record |
| Unsubscribe URLs, preference pages, SMS and WhatsApp opt-outs | End-user driven |
| Landing page forms, paired with an Automation Event-Triggered Flow | End-user driven |
| Consent Request / Create Consent flow action | Automation |
The flow action is available in Data Cloud-Triggered Flows, Automation Event-Triggered Flows (including form-triggered), On-Demand Flows and Record-Triggered Flows (from Winter β27 Release).
Unsupported Methods
Each of these writes to Data 360 storage directly, and leaves the cache exactly as it was:
| Method | Why it fails |
|---|---|
| Data stream mapped directly to the consent DLO | Bypasses the consent service |
| Data 360 Bulk Ingestion API writing to the consent DMO | Bypasses the consent service |
| Batch Data Transforms updating a mapped DLO | Bypasses the consent service |
Legacy MessagingConsent and MessagingConsentV2 flow actions | Write to the DLO instead of calling the service |
| External system writing into the consent DMO | Bypasses the consent service |
The legacy flow actions deserve a warning of their own. MessagingConsent and MessagingConsentV2 are still visible in Flow Builder, and they were the documented approach for a period before the Create Consent action existed. Salesforce now answers it directly β these methods are not supported, because they write to the data lake object instead of going through the service.
There is no cache flush, so if you want to fix it, you re-issue every affected consent change through a supported method and let the service update the cache as a side effect. For a handful of records the component is fine. For anything larger, Salesforce recommends a Data Cloud-Triggered Flow calling Create Consent across the affected population. The CSV import is the other practical replay tool, under the same per-file rules as the initial load.
Where to Find Consent Data
On the Contact, Lead or Prospect record
The Privacy Consent Status component lists subscriptions and their consent values, and is available on Lead, Contact and Person Account record pages (add it through Object Manager, Lightning Record Pages). It matches the recordβs email against the consent data per subscription, and shows opted out whenever it finds nothing.
In Data Explorer
Data Explorer against the Communication Subscription Consent DMO gives you current state. Search on the contact point value, since thatβs what the key is built from.
Using Query Editor
The SQL for joining consent back to an Individual or Unified Individual is in How the Objects Connect above. Query Editor is also where you go for anything the audit trail holds, since Data Explorer wonβt show it.
Historical data
Consent records work as an upsert, so the DMO holds current state and not a trail. History lives in Consent Audit Trail, which is a data lake object that is not mapped to any DMO.
Two fields in there are more useful than they look. PassedConsentStatus holds the status the calling application submitted, sitting right next to ConsentStatus, which holds the result. When those two disagree, you are looking at a write that didnβt land the way its caller thought it did. And ConsentCapturedSourceType, SourceName and SourceDetails carry source attribution, but only if whatever wrote the record bothered to populate them.
What You Canβt See
- Who changed it. There is no UserId, ActorId or ModifiedById field on the audit trail, and Salesforce describes that as by design for the current schema. The source attribution fields are the closest substitute, and they are only ever as good as the flow or integration that filled them in. If you need actor-level attribution for compliance, you are building it yourself.
- A consent history view on the record β listed as a known request on the roadmap, with no committed date.
- The cache β there is no way to inspect what the send engine currently believes about an address.
- More than 100 consent records on a record page. The component says so in its own banner β it shows the 100 most recent and doesnβt tell you what it left out.
- Anything in the Party field π€·ββοΈ
Summary
Marketing Cloud Next keeps its own small consent model next to the platformβs much larger one, and reads nothing from it. Almost every surprise in this article comes from that.
The three rules again:
- Consent belongs to a contact point value, not a person. Change someoneβs email and the consent stays on the old address.
- No consent record means opted out. On day one that is your entire database.
- At send time the source of truth is a cache, not the record. It can be 90 days stale.
Then it comes down to which writes count. CSV import, the Privacy Consent Status component, preference pages, unsubscribe links, the Create Consent flow action β all of these go through the consent service and refresh the cache. Data streams onto the consent DLO, the Bulk Ingestion API, Batch Data Transforms, the legacy MessagingConsent actions, anything external writing straight to the DMO β none of them do.
Some of it you only get one shot at. Scope is fixed at creation, deleting a subscription deletes its consent data, and audit rows need a support case to remove. Treat the initial import as permanent.
And there are four things you currently canβt see β the cache, who changed a record, consent history on the record, and anything in the Party field. π€·ββοΈ
Open Questions
Two things I havenβt been able to settle.
Does the 90-day cache clock run from the write or from the last read, and does a send refresh the entry? If it resets on read, then 90 days is a floor rather than a ceiling, and a frequently mailed address could hold a stale value for far longer than three months.
What happens to consent when two Contacts with different email addresses are merged? Nothing in the documentation covers it, and the answer matters to anyone running deduplication at any scale.
If youβve measured either of these, Iβd like to hear about it.