All articles
Engineering12 min read

Syncing consent across your CRM, CDP and marketing stack

The banner is solved. The hard part is the twelve systems downstream that each cached a stale answer — and the delivery guarantees that keep them honest.

ConsentCenter Engineering

Platform Engineering

Share

Consent propagation is a distributed-systems problem wearing a compliance hat. The moment a withdrawal is recorded, you have an unbounded set of consumers holding a value that is now wrong, and a legal obligation with a clock on it. Treating this as an integration checklist rather than a consistency problem is why so many programmes leak.

Push, pull, or both

ModelLatencyFailure mode
Push (webhook / event)SecondsSilent drop — the consumer never knows it missed an update
Pull (check at use time)Zero stalenessAvailability coupling — your consent API becomes a hard dependency on send
Push + periodic reconciliationSeconds, self-healingMore moving parts, but drift is bounded and detectable

Push plus reconciliation is the only model that survives contact with real vendor APIs. Push gives you the latency you need for withdrawals; reconciliation catches everything the push layer lost to a 503, a rate limit or a silently deprecated webhook endpoint.

Design the event so it cannot be applied out of order

Consent events arrive out of order. Always. A retry from three minutes ago will land after the update that superseded it, and if your consumers apply last-write-wins on arrival time, you will re-enable marketing for someone who opted out.

javascript
// Every consumer applies the same rule: version wins, not arrival time.
function applyConsentEvent(current, incoming) {
  if (current && incoming.version <= current.version) {
    return current; // stale replay — drop it
  }
  return {
    subjectId: incoming.subjectId,
    purpose: incoming.purpose,
    granted: incoming.decision === 'granted',
    version: incoming.version,
    appliedAt: incoming.collectedAt,
  };
}

Idempotency is not optional

At-least-once delivery means every consumer will see duplicates. A monotonic version per (subject, purpose) plus an idempotency key on the event makes duplicate delivery a no-op instead of a race.

Identity is the actual hard part

Your CRM keys on email. Your CDP keys on an internal ID. Your ad platform keys on a hashed email that was normalised differently. A consent event that cannot be resolved to the right record in each system is a consent event that silently does nothing.

  • Normalise before hashing — lowercase, trim, strip gmail dots — and document the exact recipe. A mismatched normalisation is invisible and total.
  • Carry every known identifier on the event rather than making each consumer do a lookup.
  • Treat an unresolvable subject as a hard failure with an alert, never a silent skip. A skipped withdrawal is the expensive kind of bug.
  • Reconcile identity graphs on a schedule; merges and splits happen constantly and they orphan consent.

Fail closed on the way out

If the consent lookup fails at send time, the safe default is to not send. This is uncomfortable for growth teams and non-negotiable in practice: an unsent email is a metric, a non-consented one is a breach. Cache aggressively so the fail-closed path is rare, but make it the path.

javascript
async function canSend(subjectId, purpose) {
  try {
    const consent = await consentCache.get(subjectId, purpose, { maxAgeMs: 60_000 });
    return consent?.granted === true;
  } catch (error) {
    logger.error({ err: error, subjectId, purpose }, 'consent lookup failed');
    return false; // fail closed — never "assume yes" on error
  }
}

What to monitor

  1. 1Propagation lag, p99, per downstream system — the number that matters for withdrawal obligations.
  2. 2Reconciliation drift count. Should trend to zero; a rising floor means a push path is quietly broken.
  3. 3Unresolved-identity rate. A step change here almost always precedes a data incident.
  4. 4Fail-closed rate at send time. Should be near zero; if it is not, your cache strategy is wrong.

A consent decision that has not reached the system acting on the data has not been honoured — regardless of what your dashboard says.

TopicsIntegrationCRMCDPArchitecture

Last updated .

Put this into practice

ConsentCenter handles region-aware consent, downstream synchronisation and audit evidence as one connected platform — so the patterns in this article are the default, not a project.