A Technical Overview of the List Manager in Sitecore 8.2

The Sitecore List Manager is used to create and manage lists of contacts for engagement plans and targeted email campaigns.

Contact Lists

Contact Lists are the building block of targeted email campaigns. They are lists made of identified users of the website or any contact that has been manually added to the list.

Note that any manually created contact added to a list is also added as a contact to the website.

All contact lists are stored under Sitecore / System / List Manager / All Lists in the Content Tree. You may notice that the tree items don't have any children.

It turns out that contact lists store their children directly in the XDB rather than in Sitecore itself. Each contact in XDB has a tag corresponding to the lists that they are in. They can be found in the analytics database in MongoDb.

To avoid slow queries to MongoDb, Sitecore indexes the contacts in the sitecore_analytics_index Solr index. Sitecore generates a query similar to the following:

q=(type_t:(contact) AND (contact.tags_sm:(ContactLists\:\{BBB9C339\-F81B\-4635\-876F\-24EBDEEA38DA\}) OR (contact.tags_sm:(\{BBB9C339\-F81B\-4635\-876F\-24EBDEEA38DA\}) AND contact.tags_sm:(ContactLists~0.5))))

This also explains why the List Manager is slow to update when adding or removing contacts. The screen is entirely based off the index. Re-indexing needs to occur before the screen is updated.

Segmented Lists

Segmented lists are lists based upon Contact Lists. They typically have some business logic applied to them. A good example would be lists of recent engagement times:

  • 0 to 30 Days
  • 31 to 60 Days
  • 61 to 90 Days

The lists can be confirgured in the List Manager using the Segment Builder:

If you look behind the scenes you will notice that contacts in Segmented Lists are not stored as tags on the contact. This is due to the fact that the lists can change frequently based upon the rules configured on the list. The individual contact data from each visit to the website is indexed in Solr from the XDB.

The indexed data is then queried by Sitecore with the filters selected in the Segment Builder:

(((type_t:(contact) AND contact.visitcount_tl:[5 TO *]) AND (contact.tags_sm:(ContactLists\:\{BBB9C339\-F81B\-4635\-876F\-24EBDEEA38DA\}) OR (contact.tags_sm:(\{BBB9C339\-F81B\-4635\-876F\-24EBDEEA38DA\}) AND contact.tags_sm:(ContactLists~0.5)))) AND contact.preferredemail_t:[* TO *])

The above query shows a simple example for a list that displays only contacts that have visited the site at least 5 times.

Accessing Lists in Code

There are two important use cases for using the List Manager in code. The first is basic CRUD operations (create, read, update, delete). The second is detecting when a contact has been added or removed from a list.

It can be tempting to skip the Sitecore APIs and go directly to XDB or the Solr index. That should be avoided though as Sitecore may significantly change fields/locations/etc of the analytics databases.

CRUD Operations can be done via the Sitecore.ListManagement.ListManager class. It can be instantiated like so:

// needs the following namespaces:

// Sitecore.Configuration
// Sitecore.ListManagement
// Sitecore.ListManagement.ContentSearch.Model

var listManager = Factory.CreateObject("contactListManager", false) as ListManager<Sitecore.ListManagement.ContentSearch.Model.ContactList, ContactData>;

Key methods on the ListManager class include but aren't limited to:

// Add a contact to a list
SubscribeContact(Sitecore.ListManagement.ContentSearch.Model.ContactList list, Contact contact)

// remove a contact from a list
UnsubscribeContact(Sitecore.ListManagement.ContentSearch.Model.ContactList list, Contact contact)

// get a list by the list id
FindById(string listId)

Detecting when a contact is added or removed from a list they can be handled in the following pipelines:

<listManagement.removeContactAssociations patch:source="Sitecore.ListManagement.config">
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.Common.GetContactListRecipientsCount, Sitecore.ListManagement.ContentSearch"/>
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.RemoveContactAssociations.RemoveAssociationsFromIndex, Sitecore.ListManagement.ContentSearch">
    <ContactRepository ref="contactRepository"/>
    <ContactProcessingProvider ref="processContactsDataProvider"/>
    </processor>
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.Common.UpdateContactListRecipientsCount, Sitecore.ListManagement.ContentSearch"/>
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.Common.UpdateContactListBulkOperationsId, Sitecore.ListManagement.ContentSearch"/>
</listManagement.removeContactAssociations>

and

<listManagement.updateContactAssociations patch:source="Sitecore.ListManagement.config">
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.UpdateContactAssociations.CheckListSourceChanged, Sitecore.ListManagement.ContentSearch"/>
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.UpdateContactAssociations.DetectContactAssociationsChanges, Sitecore.ListManagement.ContentSearch"/>
    <processor type="Sitecore.ListManagement.ContentSearch.Pipelines.UpdateContactAssociations.ApplyContactAssociationsChanges, Sitecore.ListManagement.ContentSearch"/>
</listManagement.updateContactAssociations>

Summing it Up

  1. The system of record is the XDB
  2. The data is accessed through Solr
  3. It is best practice to access the data through Sitecore's APIs rather than directly
A Technical Overview of the List Manager in Sitecore 8.2
Share this