Does anyone know how delete/remove a xDB Contact programmatically in Sitecore (8.1+), which also ensures a correct (re)-indexing?

Or, is there another strategy? Such as scrambling the identifier? - or - merging it into void?

  • 3
    Could you provide a bit more info on what you're trying to achieve by deleting the contact?
    – Ian Graham
    Commented Nov 9, 2016 at 19:36
  • As Ian has asked, please provide context. There is always a better solution than deleting a contact. We just need to know what you are attempting to achieve. Commented Nov 17, 2016 at 15:28

2 Answers 2

Sitecore.Analytics.Data.DataAccess.DataAdapterManager.Provider.DeleteContact(new ID(contactId));

After that you might run the following to update the index:

var index = Sitecore.ContentSearch.ContentSearchManager.GetAnalyticsIndex();

But note that it is time and resource consuming.

  • Do you know the effect on the analytics index and reporting database? I could imagine it would break. Commented Nov 10, 2016 at 15:09
  • We use this approach when user wants to delete his account from the site and exm mail-outs. Yes, I think this can affect analytics reports (some not matching values) but it is more important to remove user from the xDB if he wants.
    – Daniil
    Commented Nov 10, 2016 at 15:21
  • 1
    I don't believe index.Refresh() will do anything useful, at all. It will NOT reindex all contacts. The only way to rebuild the Analytics index is to rebuild the Reporting database. Commented Nov 17, 2016 at 15:24
  • Analytics index is rebuilding constantly in background on our env. I think it is different process. And we do not need to rebuild reporting db to get new profile facets for segmentation.
    – Daniil
    Commented Nov 17, 2016 at 16:14
  • The Analytics index is not rebuilding constantly, it's building. I'll refer you to my previous answer for more details about how exactly data gets into this index. Also, check out this post by Adam Conn. The bottom line is, index.Refresh() will not make deleted contacts disappear from the index. You're free to test it yourself if you don't believe me :) Commented Nov 18, 2016 at 7:14

Do not delete contacts

Simply deleting a contact is a bad idea. It doesn't take into account so many entities that are related to the contact! Here's a very incomplete list of things to consider:

  • The contact's interactions will remain in the xDB. They'll continue to be associated with the non-existing contact, which may result in run-time errors.
  • The aggregated data in the RDB will not get updated. This will especially be a problem if you mass-delete contacts.
  • If the contact was merged with another contact before, the old contact record will now contain a broken link. If something in the system attempts to get the old contact by ID, normally that would result in a "redirect" to the new contact. Now this will lead to an exception.
  • The Analytics index will still store information about the contact. Doing index.Refresh(); will NOT remove the contact from the index.
  • If the contact has a live session on the site, then when the session ends it will be recreated.
  • The numerous applications and workers that may be using the contact at the time of deletion will crash.
  • The contact processing pools may still have references to the contact.
  • Etc, etc, etc.

All in all, it's virtually impossible to clean up every single link to the contact. So sooner or later there will be errors and you won't have any idea where they are coming from.

Do not delete contacts.


Do not delete contacts. Really, just don't. Consider why you want to do it and you'll most likely find there's no reason to.

1) Make the contact anonymous

If you want to "unregister" a contact, you can always remove its identifier and make it anonymous:

ContactRepositoryBase contactRepository = Factory.CreateObject("contactRepository", true) as ContactRepositoryBase;

LeaseOwner leaseOwner = new LeaseOwner("YOUR_WORKER_NAME", LeaseOwnerType.OutOfRequestWorker);
LockAttemptResult<Contact> lockResult = contactRepository.TryLoadContact(email, leaseOwner, TimeSpan.FromMinutes(1));

Contact contact = lockResult.Object;

if (lockResult.Status == LockAttemptStatus.Success)
    // Make the contact anonymous.
    contact.Identifiers.Identifier = null;
    contact.Identifiers.IdentificationLevel = ContactIdentificationLevel.Anonymous;

    // Save and release the contact.
    var options = new ContactSaveOptions(release: true, owner: leaseOwner);
    contactRepository.SaveContact(contact, options);

2) Reduce the size of the Analytics index.

If your Analytics index grows too large, consider upgrading to Sitecore 8.1 Update 3 or Sitecore 8.2. There's a setting named ContentSearch.Analytics.IndexAnonymousContacts that will greatly reduce the amount of indexed contacts.

3) Obsolete the contact

If you really want to make it seem like the contact doesn't exist anymore, here's what you can do:

using Sitecore.Analytics.Model;
using Sitecore.Analytics.Data.DataAccess;

// ...

ContactRepositoryBase contactRepository = Factory.CreateObject("contactRepository", true) as ContactRepositoryBase;

LeaseOwner leaseOwner = new LeaseOwner("YOUR_WORKER_NAME", LeaseOwnerType.OutOfRequestWorker);

contactRepository.ObsoleteContact(obsoleteContactId, leaseOwner, successorContactId);

The successorContactId should contain an ID of an existing contact. The contact with obsoleteContactId will be "merged" into the the successor contact. The benefit of this approach is that the obsolete contact will be scheduled for processing as obsoleted which should remove it from the Analytics index and (hopefully) properly update the RDB statistics.

Do not delete contacts.

  • I completely agree with you that it is bad idea to delete contact but it can be requirement of lawyers . Thank you for sharing contactRepository.ObsoleteContact method. Can you please clarify what is "YOUR_WORKER_NAME" ?
    – Daniil
    Commented Nov 17, 2016 at 16:14
  • @Daniil this is just a string that identifies the lease holder. It needs to be unique per process. Commented Nov 17, 2016 at 19:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.