---
title: Implementing personal data erasure
related:
  - https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance.md
  - https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/personal-data-in-xperience.md
  - https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

> **Info:** **Enterprise license required**
>
> Features described on this page require the **Kentico Xperience Enterprise** license.

To comply with the requirements of personal data regulations, such as the [GDPR](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance.md), you need to provide a way for administrators (data protection officers) to erase personal data stored within the system. This is necessary to fulfill the "right to be forgotten" of your website's visitors and users, i.e. when resolving requests to delete personal data for specific data subjects.

By default, Xperience does not provide any functionality for erasing personal data. You need to implement the data erasure based on exact knowledge of your specific website, including the following factors:

- How the website gathers, processes and stores personal data
- The nature of the legal requirements that you wish to fulfill
- Other legal considerations that allow or require the website's owner to hold personal data (for example e-commerce records for accounting purposes, etc.)

Depending on these requirements, your personal data erasure functionality may need to completely delete objects, clear values of individual object fields (columns), or perform anonymization of certain types of data while retaining others.

> **Info:** See the [Personal data in Xperience](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/personal-data-in-xperience.md) reference to learn how the system gathers, stores and uses personal data by default. The information may be helpful when planning the data erasure functionality for your website.

Use the following process to develop the personal data erasure:

> **Note:** **Prerequisite**: Before you start implementing personal data erasure, you need to prepare functionality that identifies and collects the given data. For detailed information, see [Implementing personal data collection](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md).

1. Open your Xperience administration solution in Visual Studio.
2. Create custom classes that perform the required delete actions – _Data erasers_. See the [Creating data erasers](#creating-data-erasers) section for details.

   > **Tip:** **Class location**
   >
   > Add the custom classes as part of a new assembly (_Class library_ project) in your Xperience solution. You need to add the appropriate references to both the assembly and the main Xperience administration project (CMSApp).
3. Create a custom control in the Xperience project to define the options that users can configure when deleting personal data. See [Defining the eraser configuration](#defining-the-eraser-configuration).
4. Add a [custom module class](https://docs.kentico.com/13/custom-development/creating-custom-modules/initializing-modules-to-run-custom-code.md) or edit an existing one. Register your data eraser implementations and eraser configuration control within the module's **OnInit** method:
   - You can register any number of data erasers and a single configuration control.
   - To register data erasers, call the **PersonalDataEraserRegister.Instance.Add** method (available in the **CMS.DataProtection** namespace). The system runs the delete actions defined within individual erasers according to the registration order (starting from the first data eraser to the last).
   - To register your eraser configuration control, call the **DataProtectionControlsRegister.Instance.RegisterErasureConfigurationControl** method (available in the **CMS.UIControls** namespace). Specify the path of the user control file in the method's parameter.

Users can now delete personal data on the **Right to be forgotten** tab of the **Data protection** application. The registered configuration control defines the content of the dialog where users choose which types of data are erased, and the data eraser implementations then perform the corresponding delete actions.

## Creating data erasers

When deleting personal data in the **Data protection** application, users first submit real-world identifiers to find the appropriate data within the system. The registered _Identity collectors_ (see [Implementing personal data collection](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md)) convert these identifiers into Xperience objects, and _Data collectors_ return the related personal data. To allow users to delete the collected data, you need to create _Data erasers_.

Data erasers are classes that implement the **IPersonalDataEraser** interface (available in the **CMS.DataProtection** namespace). Every implementation must contain the **Erase** method, which processes the following parameters:

- **IEnumerable** – provides the identity objects that were added by your _IIdentityCollector_ implementations. You can convert the _BaseInfo_ objects to specific types, such as _UserInfo, ContactInfo,_ etc.
- **IDictionary** – a dictionary containing keys and values that were submitted in the eraser configuration dialog (see [Defining the eraser configuration](#defining-the-eraser-configuration)).

The content of the _Erase_ method depends on your requirements. Based on the method's parameters, you can completely delete objects, assign empty values to individual object fields (columns), or perform more complex anonymization of data.

When erasing personal data, make sure you delete objects including their [version history](https://docs.kentico.com/13/configuring-xperience/working-with-object-versioning.md) and without creating [recycle bin](https://docs.kentico.com/13/configuring-xperience/working-with-object-versioning/objects-recycle-bin.md) records. You can achieve this by using the standard [Provider API](https://docs.kentico.com/13/custom-development/database-table-api.md) to delete objects and wrapping the code into a **CMSActionContext** block with the **CreateVersion** property set to _false_:

```csharp

using (new CMS.Base.CMSActionContext() { CreateVersion = false })
{
    ...
}

```

Also consider the parent-child relationships and other dependencies between objects. When you delete an object, all child objects and other objects that have a required dependency on the given object are also deleted. This may have an effect on the order in which you need to delete different types of objects within the _Erase_ method, or even on the registration order of your _IPersonalDataEraser_ implementations.

> **Info:** See the [Example - Creating a contact data eraser](#example-creating-a-contact-data-eraser) section to view a code example.

## Defining the eraser configuration

The **Data protection** application provides an interface where users can choose which types of personal data they want to erase or set other configuration options. You need to create a custom control that provides the content of this interface based on the functionality of your [Data erasers](#creating-data-erasers):

1. Create a Web User Control (.ascx file) in the Xperience administration project (_CMSApp_).
2. Add components to the control's markup that allow users to set the required configuration options.
3. Switch to the code behind and make the control class inherit from **ErasureConfigurationControl** (available in the **CMS.UIControls** namespace).
4. Override the following methods:
   - **GetConfiguration** – return an _IDictionary_ collection containing all configuration values that users input through the control.
   - **IsValid** – return a _bool_ value that indicates whether the control's input is valid. Call the _AddError_ method to display messages to users in cases where the input is not valid.

Once your custom control is registered, the system uses it when displaying the **Select data to delete** dialog in the **Data protection** application. The keys and values added via the control's **GetConfiguration** method are available as the second parameter of the **Erase** method in your **IPersonalDataEraser** implementations.

> **Info:** See the [Example - Creating a contact data eraser](#example-creating-a-contact-data-eraser) section to view a code example.

## Example – Creating a contact data eraser

The following example demonstrates how to implement a personal data eraser for [contacts](https://docs.kentico.com/13/on-line-marketing-features/managing-your-on-line-marketing-features/contact-management/working-with-contacts.md) and their logged [activities](https://docs.kentico.com/13/on-line-marketing-features/managing-your-on-line-marketing-features/contact-management/tracking-contact-activities.md). The sample eraser extends the example from the [Implementing personal data collection](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md) page – the collectors find contact data based on an email address identifier, and the eraser allows users to delete the given contacts and/or their activities (on the **Right to be forgotten** tab of the **Data protection** application).

> **Info:** This example only shows the basic implementation concepts and deletes a very limited set of personal data. You can find a more extensive code example in your Xperience program files directory (by default _C:\Program Files\Kentico\\_) under the **CodeSamples\CustomizationSamples\DataProtection** subfolder.
>
> Keep in mind that you always need to adjust your own implementation based on the personal data processing used on your website and the legal requirements that you wish to fulfill.

### Setting up a class library and data collectors

Before you can start creating the eraser, you need to implement data collection functionality:

1. Recreate or reuse the entire custom project described in [Example - Creating contact data collectors](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md#example-creating-contact-data-collectors) (including the _IIdentityCollector_ and _IPersonalDataCollector_ implementations, and the custom module class used for registration).
2. Add additional references to required Xperience libraries (DLLs) for the project:

   1. Right-click the custom project and select **Add -> Reference**.
   2. Select the **Browse** tab of the **Reference manager** dialog, click **Browse** and navigate to the  _**Lib**_  folder of your Xperience project.
   3. Add references to the following libraries (in addition to the libraries already referenced in the original example):
      - **CMS.Activities.dll**
      - **CMS.UIControls.dll**

### Creating the data eraser

Add a new class implementing the **IPersonalDataEraser** interface under the custom project:

```csharp

using System.Collections.Generic;
using System.Linq;

using CMS.Activities;
using CMS.Base;
using CMS.ContactManagement;
using CMS.DataEngine;
using CMS.DataProtection;
using CMS.Helpers;

public class ContactDataEraser : IPersonalDataEraser
{
    public void Erase(IEnumerable<BaseInfo> identities, IDictionary<string, object> configuration)
    {
        // Gets all contact objects added by registered IIdentityCollector implementations
        var contacts = identities.OfType<ContactInfo>();

        // Does nothing if no contacts were collected
        if (!contacts.Any())
        {
            return;
        }

        // Gets a list of identifiers for the contacts
        List<int> contactIds = contacts.Select(c => c.ContactID).ToList();

        // The context ensures that objects are permanently deleted with all versions, without creating recycle bin records
        // Contact and activity objects do not support versioning,
        // but we recommend using this action context in general when deleting personal data
        using (new CMSActionContext() { CreateVersion = false })
        {
            // Deletes the activities of the given contacts (if enabled in the configuration)
            DeleteActivities(contactIds, configuration);

            // Deletes the given contacts (if enabled in the configuration)
            // Also automatically deletes activities of the given contacts (contacts are parent objects of activities)
            DeleteContacts(contacts, configuration);
        }
    }

    private void DeleteActivities(List<int> contactIds, IDictionary<string, object> configuration)
    {
        // Checks whether deletion of activities is enabled in the configuration options
        object deleteActivities;
        if (configuration.TryGetValue("deleteActivities", out deleteActivities)
            && ValidationHelper.GetBoolean(deleteActivities, false))
        {            
            // Deletes the activities of the specified contacts
            // The system may contain a very large number of activity records, so the example uses the BulkDelete API
            // This is more efficient, but does not perform general actions, such as logging of synchronization tasks
            ActivityInfoProvider.ProviderObject.BulkDelete(
                new WhereCondition().WhereIn("ActivityContactID", contactIds));
        }
    }

    private static void DeleteContacts(IEnumerable<ContactInfo> contacts, IDictionary<string, object> configuration)
    {
        // Checks whether deletion of contacts is enabled in the configuration options
        object deleteContacts;
        if (configuration.TryGetValue("deleteContacts", out deleteContacts)
            && ValidationHelper.GetBoolean(deleteContacts, false))
        {
            // Deletes the specified contacts
            foreach (ContactInfo contact in contacts)
            {
                ContactInfo.Provider.Delete(contact);
            }
        }
    }
}

```

The sample data eraser processes the contact objects provided by the registered identity collector (see [Example - Creating contact data collectors](https://docs.kentico.com/13/configuring-xperience/data-protection/gdpr-compliance/implementing-personal-data-collection.md#example-creating-contact-data-collectors) for details). The eraser then deletes the contacts and/or their logged activities according to configuration options, which are supplied by users through a dialog generated by a custom control.

### Creating the eraser configuration control

To allow users to configure which objects are deleted, you need to create a custom control:

1. Create a _Web User Control_ in the Xperience administration project (_CMSApp_), for example named _ContactDataEraserConfiguration.ascx_.

   - We recommend adding the control under a custom folder related to your data protection module, for example: _\~/CMSModules/CustomDataProtection_
2. Add the following markup to the control:

   ```xml

   <div class="cms-bootstrap">
       <div class="form-horizontal">
           <cms:LocalizedHeading runat="server" Level="4" Text="Contact data" />
           <cms:CMSCheckBox ID="chbDeleteContacts" runat="server" Text="Delete contacts" />
           <cms:CMSCheckBox ID="chbDeleteActivities" runat="server" Text="Delete contact activities" />
       </div>        
   </div>

   ```
3. Switch to the control's code behind. Make the control class inherit from **ErasureConfigurationControl**, with the following code:

   ```csharp

   using System.Collections.Generic;

   using CMS.UIControls;

   public partial class CMSModules_CustomDataProtection_ContactDataEraserConfiguration : ErasureConfigurationControl
   {
       // Fills the eraser configuration based on the user's input    
       public override IDictionary<string, object> GetConfiguration(IDictionary<string, object> configuration)
       {
           // The configuration keys must match the values checked in your IPersonalDataEraser implementations
           configuration.Add("deleteContacts", chbDeleteContacts.Checked);
           configuration.Add("deleteActivities", chbDeleteActivities.Checked);

           return configuration;
       }

       // Validates the eraser configuration provider by the user
       public override bool IsValid()
       {
           // Validates that at least one deletion checkbox is selected
           bool isValid = chbDeleteContacts.Checked || chbDeleteActivities.Checked;

           if (!isValid )
           {
               // Adds an error message that the control displays when the validation fails
               AddError("No data was selected for deletion.");
           }

           return isValid;
       }
   }

   ```
4. Save the control files and Rebuild the solution.

The control provides an interface where users can select whether to delete contacts and activities.

### Registering the eraser and configuration control

To register the personal data eraser and its configuration control, edit the [module class](https://docs.kentico.com/13/custom-development/creating-custom-modules/initializing-modules-to-run-custom-code.md) under the custom project and expand the initialization code in the **OnInit** method:

```csharp

using CMS;
using CMS.DataEngine;
using CMS.DataProtection;

using CMS.UIControls;

// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomDataProtectionModule))]

internal class CustomDataProtectionModule : Module
{
    // Module class constructor, the system registers the module under the name "CustomDataProtection"
    public CustomDataProtectionModule()
        : base("CustomDataProtection")
    {
    }

    // Contains initialization code that is executed when the application starts
    protected override void OnInit()
    {
        base.OnInit();

        // Adds the ContactIdentityCollector to the collection of registered identity collectors
        IdentityCollectorRegister.Instance.Add(new ContactIdentityCollector());

        // Adds the ContactDataCollector to the collection of registered personal data collectors
        PersonalDataCollectorRegister.Instance.Add(new ContactDataCollector());

        // Adds the ContactDataEraser to the collection of registered personal data erasers
        PersonalDataEraserRegister.Instance.Add(new ContactDataEraser());

        // Registers the custom eraser configuration control
        DataProtectionControlsRegister.Instance.RegisterErasureConfigurationControl("\\~/CMSModules/CustomDataProtection/ContactDataEraserConfiguration.ascx");
    }
}

```

Save all changes and **Build** the custom project.

You can now delete personal data for contacts and their activities in the **Data protection** application. On the application's **Right to be forgotten** tab, you can search for data based on an email addresses. If matching contacts exist in the system, the sample collectors display their data in plain text format, and you can click **Select data to delete** to open the eraser configuration dialog.

![Using the sample eraser to delete contact personal data in the Data protection application](https://docs.kentico.com/docsassets/13/implementing-personal-data-erasure/personal_data_erasing.png "Using the sample eraser to delete contact personal data in the Data protection application")

Submitting the dialog sends the collected data and selected configuration options to the registered eraser implementation, which performs the corresponding delete actions.

> **Info:** **Note**: Contacts have a parent-child relationship with activities. If you delete a contact object, all of the activities logged for the given contact are also deleted automatically. However, the configuration dialog allows you to delete activities while retaining contacts.
