SfSkills Domains Docs GitHub

Home / security / gdpr-data-privacy

gdpr-data-privacy

Use this skill when implementing GDPR or CCPA data privacy controls in Salesforce: Individual sObject linkage, consent tracking, Right to Be Forgotten (RTBF) requests, data subject request handling, and Privacy Center configuration. Trigger keywords: GDPR, consent management, Individual object, ContactPointConsent, ShouldForget, Privacy Center. NOT for field-level encryption — use security/platform-encryption. NOT for sandbox data masking — use security/sandbox-data-masking. NOT for the intake-to-fulfilment request workflow — use security/customer-data-request-workflow.

Open the skill folder on GitHub


GDPR Data Privacy

Use this skill when a practitioner needs to implement GDPR or CCPA data privacy controls inside Salesforce: linking personal data to the Individual sObject, tracking consent through the native consent model, handling Right to Be Forgotten (RTBF) requests, processing data subject requests, or evaluating whether Privacy Center is required.


Before Starting

Gather this context before working on anything in this domain:


Core Concepts

The Individual sObject (API v42+)

The Individual sObject (Individual) is a first-party Salesforce object that acts as the privacy and consent container for a natural person. It stores privacy preference flags at the person level rather than duplicating them on every related record.

Key fields on Individual:

Contact, Lead, and PersonAccount each carry an IndividualId lookup field. Set this field to associate a person record with their Individual privacy container. One Individual record should represent one natural person; do not share a single Individual across multiple people.

Salesforce provides two objects for fine-grained consent tracking:

ContactPointTypeConsent — channel-level consent. Represents a person's blanket opt-in or opt-out for a communication channel (e.g., "opted out of all email"). Key fields:

ContactPointConsent — contact-point-specific consent. Represents consent for a specific email address, phone number, or other contact point. Key fields:

Use ContactPointTypeConsent for channel-level blanket preferences. Use ContactPointConsent when you need per-address granularity or need to track consent for a specific processing purpose.

Right to Be Forgotten: Platform Behavior vs. Automation

RTBF (right to erasure) under GDPR Article 17 requires that personal data be deleted or anonymized when a data subject requests it and no legitimate retention basis overrides the request.

Salesforce does not automatically respond to ShouldForget = true. You need one of:

  1. Privacy Center (licensed add-on): Provides a no-code policy engine. You define Erasure Policies that specify which objects and fields to delete or anonymize, and Privacy Center runs the erasure asynchronously when triggered by a Data Subject Request (DSR) record. Also provides Data Portability (export all data for a subject).
  2. Custom Batch Apex: Without Privacy Center, you must write a Database.Batchable class that queries for records linked to Individuals where ShouldForget = true, then deletes or anonymizes them. This path requires careful handling of referential integrity and governor limits.

Anonymization over hard delete: In most orgs, hard-deleting a Contact breaks Opportunity, Case, and Order foreign keys. The recommended pattern is to anonymize (tokenize) the personal data fields — replace name, email, phone, and address with non-identifying tokens — while keeping the record shell for relational integrity. Delete only records that have no referential dependencies.


Common Patterns

When to use: Initial implementation of the privacy data model for contacts or leads who are EU/EEA residents, or any org adopting explicit consent tracking.

How it works:

  1. Create an Individual record for each natural person. Set HasOptedOutOfSolicit, ShouldForget, and other flags as appropriate.
  2. Set IndividualId on the related Contact, Lead, or PersonAccount to point to the Individual record.
  3. For each communication channel the person has consented to or opted out of, create a ContactPointTypeConsent record linked via PartyId to the Individual.
  4. For specific email addresses or phone numbers with their own consent events, create ContactPointConsent records linked to the ContactPointEmail or ContactPointPhone record.
  5. Store EffectiveFrom and EffectiveTo on each consent record to represent the consent window.

Why not the alternative: Storing opt-out flags directly on Contact (e.g., HasOptedOutOfEmail) provides only a binary current state. It cannot represent time-bounded consent, per-purpose consent, or consent history. The native consent model supports audit trails and multi-channel granularity that Contact fields alone cannot provide.

Pattern 2: Right to Erasure via Batch Apex (No Privacy Center)

When to use: Orgs without Privacy Center that must respond to RTBF requests.

How it works:

// BatchForgotIndividuals.apex
// Queries Individuals with ShouldForget=true and anonymizes linked records.
// Run manually or schedule via System.scheduleBatch().

global class BatchForgotIndividuals implements Database.Batchable<SObject>, Database.Stateful {

    global Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator(
            'SELECT Id FROM Individual WHERE ShouldForget = true'
        );
    }

    global void execute(Database.BatchableContext bc, List<Individual> scope) {
        Set<Id> individualIds = new Map<Id, Individual>(scope).keySet();

        // Anonymize linked Contacts
        List<Contact> contacts = [
            SELECT Id, FirstName, LastName, Email, Phone, MailingStreet
            FROM Contact
            WHERE IndividualId IN :individualIds
        ];
        String token = 'ANON-' + System.now().getTime();
        for (Contact c : contacts) {
            c.FirstName     = 'ANON';
            c.LastName      = token;
            c.Email         = null;
            c.Phone         = null;
            c.MailingStreet = null;
        }
        update contacts;

        // Anonymize linked Leads
        List<Lead> leads = [
            SELECT Id, FirstName, LastName, Email, Phone, Street
            FROM Lead
            WHERE IndividualId IN :individualIds
                AND IsConverted = false
        ];
        for (Lead l : leads) {
            l.FirstName = 'ANON';
            l.LastName  = token;
            l.Email     = null;
            l.Phone     = null;
            l.Street    = null;
        }
        update leads;
    }

    global void finish(Database.BatchableContext bc) {
        // Optionally: send confirmation email, update DSR audit record
    }
}

Why not the alternative: Deleting Contact records breaks Opportunity, Case, and Order foreign keys, producing orphaned records or DML errors. Anonymization preserves referential integrity while fulfilling the erasure obligation for personal data fields.


Decision Guidance

SituationRecommended ApproachReason
Org is licensed for Privacy CenterUse Privacy Center RTBF Policies + DSR objectNo-code, auditable, handles data portability too
No Privacy Center, low DSR volume (<20/month)Manual Batch Apex triggered per requestProportionate; avoids over-engineering
No Privacy Center, high DSR volumeScheduled Batch Apex polling ShouldForget=truePrevents backlog; runs nightly or weekly
Need channel-level consent (email, phone)ContactPointTypeConsent per channelNative model; integrates with Marketing Cloud consent sync
Need per-address consent with use-purpose trackingContactPointConsent + DataUsePurposeRequired for GDPR Article 6 lawful-basis documentation
Personal data in custom objectsExtend Batch Apex or Privacy Center policy to custom objectsErasure obligation covers all personal data regardless of object type
Hard delete required (no referential dependencies)Delete record after verifying no FK referencesCheck lookup fields; use Database.delete with allOrNone=false

Step-by-step instructions for an AI agent or practitioner working on this task:

  1. Assess licensing and scope: Confirm whether Privacy Center is licensed. Identify all objects storing personal data (Contact, Lead, PersonAccount, custom objects). Determine which regulations apply (GDPR, CCPA, both) and whether the org processes EU/EEA residents' data.
  2. Implement the Individual data model: For each natural person, create or ensure an Individual record exists. Set IndividualId on Contact, Lead, and PersonAccount records to link them. Define a trigger or flow to create an Individual automatically when a Contact or Lead is created for a regulated person.
  3. Build the consent model: Create ContactPointTypeConsent records for each channel and each person, capturing OptInStatus, EffectiveFrom, and EffectiveTo. For specific contact points needing per-address or per-purpose consent, create ContactPointConsent records linked via DataUsePurposeId to a DataUsePurpose record that names the lawful basis.
  4. Implement RTBF handling: If Privacy Center is available, configure an Erasure Policy for each object containing personal data and create a Data Subject Request workflow. If not, write and test Batch Apex that queries Individual WHERE ShouldForget = true, anonymizes linked records on all in-scope objects, and records fulfillment in a custom audit object or custom DSR record.
  5. Handle data subject access requests (DSAR): Build an intake process (Experience Cloud form, email-to-case, or manual) that captures the data subject's identity and request type. Verify identity before processing. For data portability, Privacy Center exports a package; without it, write a report or export job across all related objects.
  6. Test and validate: In a sandbox, set ShouldForget = true on test Individual records and execute the batch or Privacy Center policy. Verify all PII fields are anonymized or deleted across Contact, Lead, and custom objects. Confirm no broken foreign keys or orphaned records.
  7. Document retention schedules: If any personal data must be retained beyond the erasure request (e.g., legal hold, financial records), document the lawful basis and configure Privacy Center retention rules or exception logic in Batch Apex. Do not silently skip erasure without a documented basis.

Review Checklist

Run through these before marking work in this area complete:


Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. ShouldForget=true does nothing on its own — Setting Individual.ShouldForget = true is a data flag, not a system action. Salesforce does not automatically delete, anonymize, or suppress any record. If your RTBF implementation relies on setting this flag without responding automation, erasure never happens.
  2. IndividualId is not auto-populated — Creating a Contact does not automatically create or link an Individual. Your org must implement a trigger or flow; Contacts created before this automation exists will have null IndividualId and be invisible to privacy-model queries.
  3. Anonymization must cover all objects — Leads, PersonAccounts, and custom objects may all hold PII. Batch jobs scoped only to Contact are incomplete; a full data model audit must precede implementation.

Output Artifacts

ArtifactDescription
Individual linkage designMapping of which Contact/Lead/PersonAccount populations need Individual records and how IndividualId will be populated
Consent object modelList of ContactPointTypeConsent and ContactPointConsent records with channel, OptInStatus, and EffectiveFrom/To per person
RTBF implementationPrivacy Center policy configuration or Batch Apex class covering all in-scope objects
DSR workflowIntake, verification, fulfillment, and audit-trail steps for Data Subject Requests
Anonymization token patternConvention for replacing PII fields (e.g., ANON-<timestamp>) consistent across objects
Retention exception registerTable of object/field combinations retained beyond erasure, with documented lawful basis

Package files