How to: Store GDPR Privacy Preferences in Salesforce

Starting from late May companies must be compliant with the new GDPR regulation. Since Winter 18 Salesforce offers a new way to track the consent of users across leads and contacts: Individual

Concept behind Individuals

In the context of clients a single human person can appear as one or multiple leads and contacts. For example in the context of a pharmaceutical company a human person can be a patient, doctor, scientist and a shareholder at the same time.


To ensure the right sharing of the person different contacts and leads have been created. In the example of a pharmaceutical company the doctor’s contact might be visible to the sales team, while the patient’s record isn’t. To make this possible multiple contacts must be created. However, it is still the same person.

When a person opts in or out of a channel / tracking this information has to be available for all different departments.

Salesforce Individuals is a simple place where all the privacy settings can be stored across multiple contacts and leads. The information is available to all departments.

6 Steps to enable Centralized Data Privacy Preferences

Step 1: Enable Individuals

The new Individual Object can be activated in the setup menu “Data Protection and Privacy”.

By enabling the checkbox the new object “Individual” becomes visible. As well 2 new lookups on Contact and Lead become available.


Step 2: Add Privacy Preferences

The Individual Object is similar to every other object. Custom Fields can be easily added and layouts adjusted.

Salesforce already provides a list of common privacy settings like Don’t Process, Don’t Profile, Don’t Solicit, Forget This Individual.

Each company has different needs then it comes to privacy settings. In some cases a date has to be associated with a setting in other cases the version of terms and services has to be stored.

Salesforce gives clients the full flexibility and allows the configuration of additional custom fields.

Note: When you add privacy relevant data to the individual don’t forget to encrypt these fields with Salesforce Shield.

Step 3: Add Individual Lookups to Contact and Lead Layout

In each page layout the new individual lookup must be added. This lookup references the individual record.

Salesforce already had some standard fields to track the out-out for eMails and Fax. These fields can be removed, since they should be migrated to individuals.


Step 5: Automate the creation of individuals

To make the use of individual records easier it makes sense to create a trigger that automatically generates an individual record in case the person is not known to the company before. Otherwise an existing individual record can be attached to the contact.

Step 6: Create Individual Records for existing Contacts and Leads

To make the implementation more uniform an individual records should exist for every contact and lead. There are two ways to run the creation of leads:

  1. ETL – With an ETL Tool like Informatica Cloud all contacts and leads are getting extracted and new individual records created. Multiple contacts and leads that are the same individual are getting lined to the same individual. The consent settings from contact and lead are getting replicated in the individual record.
  2. Batch Job – Salesforce suggests in the documentation to run a script that creates the individual records. However, it is important to note that this will work better for small and medium installations. In systems with multiple million contacts and leads ETL is the preferred option.

Extensions and other Systems

The consent to tracking is not only limited to Salesforce. Salesforce is a great place to store this information in a centralized way. With the Salesforce SOAP and REST API external applications can leverage the new feature.

Universal Log — The Next Generation Error Log based on Salesforce Platform Events

Since the beginning of APEX, developers are creating persistent event and error logs in Salesforce. Multiple Salesforce Bloggers explained their version of Error Logging in Salesforce:

All the mechanisms that have been available are using the “try-catch mechanism” and then storing a record in Salesforce. This approach comes with multiple downsides:

  • The error is getting catched and not reported to the next higher instance
  • It is impossible to see from the “Apex Job Log” if batch jobs are successful or not, since all catched exceptions are reported as “success”.
  • An additional DML operation is needed.
  • The Error Log was limited to Salesforce APEX Code

In the past this approch was the only solution to handle exceptions and store them persistent in Salesforce. But with Platform Events a new generation of Error Logging becomes possible.

Universal Log — The Next Generation Error Log

Platform Events and the Salesforce Event Bus allow the implementation of an even more sophisticated solution. I call my solution Universal Log.

My Version of the Log allows not only to store information and exceptions from APEX, the solution supports even configuration like process builder, workflows and external applications.

Architecture of Universal Log

Uniersal Log leverages the out of the box Event Bus in Salesforce. All kinds of services, such as Apex Code, Triggers, Batches, External Applications and others can create Log Events. And send them on the Event Bus. There they can be captured and translated into a persistent log.


Architecture of Universal LogUniversal Log Components

The system is based on 4 major components:

  • The Logger Class that creates based on Exceptions, Flows and other functionality Log Events
  • The Log Event that is used as a transport tool to be catched by
  • The Log Event Trigger that creates based on the event a log record
  • The Log Record That is storing the log information persistently

The Universal Logger Class

The Universal Logger Class can be called during the execution of a class similar to other error logs the error is getting catched and then logged to the log.

But with one difference: The Exception is re-thrown and becomes visible.


This simple code is going to throw an Exception. Now the universal logger sends the exceptions to the event bus and the class re-throw the exception.

    Integer i = 12/0;
catch(Exception e)
    throw e;

The re-thrown exception will be presented to the next higher level. E.g. the developer console


The universal logger take the exception and put the exception on the bus.

global class UniversalLogger
    global static void log(Exception e)
        UniversalLogEvent__e l = new UniversalLogEvent__e();
        l.Stacktrace__c = e.getStackTraceString();
} // Simplified Version

Universal Log Event Trigger

The Universal Event Log Trigger is the last component that then finally converts the Event to a persistent reocrd.

trigger UniversalLogEventTrigger on UniversalLogEvent__e (after insert)
    List<Log__c> logs = new List<Log__c>();
    for(LogEvent__e l :
        logs.add(new Log__c(Stacktrace__c = l.Stacktrace__c, ...));


Salesforce Event Bus as a base for an Error Log is a strong foundation for error logs. All kinds of applications and services can use the error log. The new error log allows to present error messages back to the user, salesforce batch log, while keeping a detailed log in a custom object.

Future Extensions

For a future Version of Universal Log I plan to integrate NewRelic to give even better visibility into the log.

Best Practice: Secure API Keys in Salesforce — Example: Google Firebase

Some time ago Salesforce introduced Named Credentials as a new way to secure secrets in Salesforce. In this post I will explain how to secure API Keys in Salesforce and make callouts to external systems without presenting the secret to developers.


In Winter ’16 Salesforce introduced Named Credentials. Before the common way to store passwords and api keys were “Custom Settings”.

Custom settings had the clear downside that username and password as well as API Keys, Tokens and oAuth Secrets where stored openly and accessible for everyone with access to custom settings.

Named Credentials in comparison do not present passwords and secrets to the user or developer.

How secure are Named Credentials?

Salesforce is recommending to use Named Credentials for all types of callouts.

Named Credentials are a safe and secure way of storing authentication data for external services called from your apex code such as authentication tokens. We do not recommend storing other types of sensitive data in this field (such as credit card information). Be aware that users with customize application permission can view named credentials, so if your security policy requires that the secrets be hidden from subscribers, then please use a protected custom metadata type or protected custom setting. For more information, see named credentials in the online help and training guide.

As mentioned by Salesforce users with “Customize Application Permissions” can view named credentials. This applies for the named credential itself.
However, when it comes to the passwords stored in named credentials, they are not visible to users or developers:

  • Credential Passwords cannot be made visible in the UI
  • Credential Passwords cannot be accessed through API
  • Credential Passwords cannot be made visible in Debug Logs

Only in the moment the HTTP Request to external systems is executed, Salesforce inserts the password into the request and sends the request to the External Service.

The External Service can then use the password or other credentials to verify the request.

Setup Named Credentials: Example Firebase

Firebase is a service by Google that can be used to send push notifications to users. Salesforce can call firebase and send a push notification to specific users.


Step 1: Setup Named Credentials

To setup the API Key I first had to setup a new server key in firebase.
(Firebase → Project Settings → Message Key)


In Salesforce the Named Credential for Firebase can be created now.
(Setup → Quick Search → Named Credentials)


The following properties have to be entered:
The Endpoint that has to be called is
As Identity Type I have chosen Named Principal, since the API key is the same for the whole org.

  • The Authentication Protocol is “Password Authentication”.
  • As Username I entered a dummy value.
  • The password is the API Key.

To use the password in the header of my request, the tick box “Allow Merge Fields in HTTP Body” must be checked.

Step 2: Callout

To be able to call Firebase, I added Firebase to my “Remote Sites” (Setup → Quick Search → Remote Site).
Sending out a request with Named Credentials is using the same functionality as in any other APEX HTTP request:

String message = ‘XYZ’;
// HTTP Request
HttpRequest req = new HttpRequest();
// Callout extended by /fcm/send
// Authentication
req.setHeader(‘Authorization’, ‘key={!$Credential.Password}’);
// send request
Http http = new Http();
HTTPResponse res = http.send(req);

As Endpoint for the HTTPRequest I used callout:Firebase. This indicates to Salesforce that the Named Credential Firebase is used.

During the execution of the HTTP request “callout:Firebase” is getting replace with the URL stored in the Named Credential. The placeholder {!$Credential.Password} is replaced by the password stored in Salesforce.

Step 3: Result

The Debug Log proofs: The request was successfully send to Firebase.



Named Credentials are the secure way to store credentials for callouts in Salesforce.