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, data privacy, consent management, right to erasure, Individual object, ContactPointConsent, ShouldForget, data subject request, Privacy Center, data portability. NOT for general data quality cleanup, duplicate management, field-level encryption (see platform-encryption skill), or sandbox data masking (see sandbox-data-masking skill).

Best use case

gdpr-data-privacy is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

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, data privacy, consent management, right to erasure, Individual object, ContactPointConsent, ShouldForget, data subject request, Privacy Center, data portability. NOT for general data quality cleanup, duplicate management, field-level encryption (see platform-encryption skill), or sandbox data masking (see sandbox-data-masking skill).

Teams using gdpr-data-privacy should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/gdpr-data-privacy/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/security/gdpr-data-privacy/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/gdpr-data-privacy/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How gdpr-data-privacy Compares

Feature / Agentgdpr-data-privacyStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

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, data privacy, consent management, right to erasure, Individual object, ContactPointConsent, ShouldForget, data subject request, Privacy Center, data portability. NOT for general data quality cleanup, duplicate management, field-level encryption (see platform-encryption skill), or sandbox data masking (see sandbox-data-masking skill).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# 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:

- Confirm whether Privacy Center is licensed. RTBF policy automation and data portability exports are only available through Privacy Center (a separately purchased add-on). Without it, all erasure logic requires custom Batch Apex.
- Identify every object that stores personal data in the org — Contact, Lead, PersonAccount, and any custom objects with PII fields. Erasure must cover all of them, not just Contact.
- Confirm the API version. The Individual sObject and IndividualId field on Contact/Lead/PersonAccount were introduced in API version 42.0 (Winter '18). Older managed packages may not expose IndividualId.
- Determine consent channels in scope. The native consent model is channel-aware: email, phone, fax, direct mail, social, and advertising are separate consent points with independent records.

---

## 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:
- `ShouldForget` (Boolean) — signals that the data subject has invoked their right to erasure. **This is a flag only. Setting it to `true` does not automatically delete or anonymize any data.** Your org must respond to this flag through Privacy Center policies or custom Batch Apex.
- `HasOptedOutOfSolicit` — general solicitation opt-out.
- `SendIndividualData` — whether data may be shared with third parties.
- `CanStorePiiElsewhere` — whether personal data may be stored outside the org's primary region.

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.

### Native Consent Model: ContactPointTypeConsent and ContactPointConsent

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:
- `ContactPointType` — channel: Email, Phone, Fax, Web, MailingAddress, Social, or EngagementChannel.
- `OptInStatus` — `OptIn`, `OptOut`, `PendingOptIn`, or `Unknown`.
- `EffectiveFrom`, `EffectiveTo` — the consent window. These allow time-bounded consent (e.g., consent valid until a specific date or renewed at re-opt-in).
- `PartyId` — lookup to the Individual record.

**ContactPointConsent** — contact-point-specific consent. Represents consent for a specific email address, phone number, or other contact point. Key fields:
- `ContactPointId` — polymorphic lookup to the specific contact point (e.g., a Contact's email address via ContactPointEmail).
- `OptInStatus`, `EffectiveFrom`, `EffectiveTo` — same semantics as ContactPointTypeConsent.
- `DataUsePurposeId` — optional link to a DataUsePurpose record describing why data is processed (maps to GDPR Article 6 lawful basis).

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

### Pattern 1: Individual Linkage and Consent Setup

**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:**

```apex
// 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

| Situation | Recommended Approach | Reason |
|---|---|---|
| Org is licensed for Privacy Center | Use Privacy Center RTBF Policies + DSR object | No-code, auditable, handles data portability too |
| No Privacy Center, low DSR volume (<20/month) | Manual Batch Apex triggered per request | Proportionate; avoids over-engineering |
| No Privacy Center, high DSR volume | Scheduled Batch Apex polling ShouldForget=true | Prevents backlog; runs nightly or weekly |
| Need channel-level consent (email, phone) | ContactPointTypeConsent per channel | Native model; integrates with Marketing Cloud consent sync |
| Need per-address consent with use-purpose tracking | ContactPointConsent + DataUsePurpose | Required for GDPR Article 6 lawful-basis documentation |
| Personal data in custom objects | Extend Batch Apex or Privacy Center policy to custom objects | Erasure obligation covers all personal data regardless of object type |
| Hard delete required (no referential dependencies) | Delete record after verifying no FK references | Check lookup fields; use Database.delete with allOrNone=false |

---

## Recommended Workflow

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:

- [ ] Every Contact, Lead, and PersonAccount representing an EU/EEA natural person has `IndividualId` populated
- [ ] `ContactPointTypeConsent` records exist for each consent channel per person, with `EffectiveFrom` and `OptInStatus` populated
- [ ] RTBF mechanism (Privacy Center policy or Batch Apex) covers all objects storing personal data — not just Contact
- [ ] Anonymization is used instead of hard delete for records with FK dependencies
- [ ] DSR intake, verification, fulfillment, and audit-trail workflow is documented and tested
- [ ] Audit trail records each RTBF execution (who requested, when fulfilled, which records affected)
- [ ] Retention exceptions (legal hold, financial records) are documented with lawful basis
- [ ] Batch Apex is governor-limit safe: uses `Database.QueryLocator`, processes in batches of 200 or fewer

---

## 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

| Artifact | Description |
|---|---|
| Individual linkage design | Mapping of which Contact/Lead/PersonAccount populations need Individual records and how IndividualId will be populated |
| Consent object model | List of ContactPointTypeConsent and ContactPointConsent records with channel, OptInStatus, and EffectiveFrom/To per person |
| RTBF implementation | Privacy Center policy configuration or Batch Apex class covering all in-scope objects |
| DSR workflow | Intake, verification, fulfillment, and audit-trail steps for Data Subject Requests |
| Anonymization token pattern | Convention for replacing PII fields (e.g., `ANON-<timestamp>`) consistent across objects |
| Retention exception register | Table of object/field combinations retained beyond erasure, with documented lawful basis |

---

## Related Skills

- `platform-encryption` — use alongside this skill when fields must be encrypted at rest; encryption does not substitute for erasure
- `sandbox-data-masking` — use to prevent real PII from entering non-production orgs; complements RTBF but is a separate concern
- `data-classification-labels` — use to tag fields containing personal data, a prerequisite for building a complete erasure scope

Related Skills

sandbox-data-masking

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring or reviewing Salesforce Data Mask to protect PII/PHI in partial or full copy sandboxes after a refresh. Trigger keywords: data mask, sandbox masking, PII in sandbox, GDPR sandbox, HIPAA non-production, mask contacts, obfuscate fields non-production. NOT for sandbox refresh mechanics (use sandbox-refresh-and-templates), NOT for production data anonymization, NOT for Shield Platform Encryption at rest.

data-classification-labels

8
from PranavNagrecha/AwesomeSalesforceSkills

Classify Salesforce fields by data sensitivity and compliance category using the four built-in classification attributes (SecurityClassification, ComplianceGroup, BusinessOwnerId, BusinessStatus). Covers Metadata API deployment, Tooling API querying, and Einstein Data Detect recommendations. NOT for data masking, Shield Platform Encryption, or runtime access control enforcement.

customer-data-request-workflow

8
from PranavNagrecha/AwesomeSalesforceSkills

Implement GDPR/CCPA data subject rights (access, deletion, rectification) using Salesforce Privacy Center and/or custom workflow. NOT for general backup or org-level data retention policy.

omnistudio-deployment-datapacks

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when exporting, importing, or version-controlling OmniStudio components using DataPacks via the OmniStudio DataPacks tool or vlocity CLI. Covers DataPack export/import, Git version control integration, CI/CD for OmniStudio. NOT for SFDX-based metadata deployment of non-OmniStudio components.

omnistudio-asynchronous-data-operations

8
from PranavNagrecha/AwesomeSalesforceSkills

Use Integration Procedures queues, DataRaptor Chain, and Remote Actions with async patterns for long-running OmniStudio flows. NOT for simple DataRaptor reads.

dataraptor-transform-optimization

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when DataRaptor Transform operations are slow, hit governor limits, or use Apex where formula fields would suffice. Covers formula vs Apex expressions, bulk transform sizing, and chained transform composition. Triggers: 'dataraptor transform slow', 'dataraptor formula vs apex', 'dataraptor bulk transform', 'dr governor limit'. NOT for DataRaptor Extract or Load performance.

dataraptor-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or reviewing OmniStudio DataRaptors, especially Extract versus Turbo Extract versus Transform versus Load, field mapping strategy, performance tradeoffs, and when to move work into Integration Procedures or Apex. Triggers: 'DataRaptor Extract', 'Turbo Extract', 'DataRaptor Load', 'DataRaptor Transform', 'OmniStudio data mapping'. NOT for overall OmniScript journey design or Integration Procedure sequencing when the main question is not the DataRaptor shape itself.

lwc-datatable-advanced

8
from PranavNagrecha/AwesomeSalesforceSkills

Advanced lightning-datatable patterns — inline edit + draftValues, custom cell types via extending LightningDatatable, sortable columns, infinite scroll with onloadmore, row-level errors, and the cost of large data sets. NOT for read-only display of small lists (plain lightning-datatable suffices) or fully custom grids (use a third-party library).

lwc-data-table

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or reviewing `lightning-datatable` usage in Lightning Web Components, including column configuration, stable `key-field` values, inline editing, row actions, infinite loading, and custom cell types. Triggers: 'lightning datatable inline edit', 'row actions in lwc datatable', 'key field missing', 'infinite loading in datatable'. NOT for highly custom virtualized grids or broad page-performance work outside the datatable boundary.

lwc-custom-datatable-types

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).

salesforce-data-pipeline-etl

8
from PranavNagrecha/AwesomeSalesforceSkills

Export large Salesforce datasets to a lakehouse via Bulk API 2.0, CDC streams, or Salesforce Data Pipelines. NOT for ad-hoc exports.

dataweave-for-apex

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when transforming structured data inside Apex — CSV → JSON, XML → SObject list, JSON → flattened CSV, or schema-mapping a third-party payload to a Salesforce model — and the existing options (`JSON.deserialize`, `Dom.Document`, hand-written loops) are getting unwieldy. Triggers: 'apex transform csv json xml without external library', 'system.dataweave script', 'salesforce native dataweave apex execute', 'transform xml to sobject apex no mulesoft', 'json reshape salesforce apex script'. NOT for MuleSoft Anypoint DataWeave running off-platform (use mulesoft-anypoint-architecture), NOT for Apex JSON serialization basics (use apex-json-serialization), NOT for Bulk API CSV ingest (use bulk-api-2-patterns).