7

When logging users in, we want to use both a userid and the user's email as contact identifiers.

// Set identifiers
Tracker.Current.Session.IdentifyAs("USERID_SOURCE", "U1542658"); 
Tracker.Current.Session.IdentifyAs("EMAIL_SOURCE", "[email protected]");

// Retrieve identifiers
var ids = Tracker.Current.Contact.Identifiers.Select(i => $"{i.Identifier} ({i.Source})"); 

ids Collection:

[email protected] (EMAIL_SOURCE)
dc1bace105fe47a286bbbe3ed64a6169 (xDB.Tracker)
24cfef12-e6ed-4043-a99c-c45a3998135f (Alias)

Unfortunately, the ids collection now only contains the second identifier "EMAIL_SOURCE". The "USERID_SOURCE" seems to be ignored.

How can we correctly set multiple identifiers?

2

2 Answers 2

4

Tracker.Current.Session.IdentifyAs() will only merge contacts if the current contact is not a known contact yet: Contact.IdentificationLevel != ContactIdentificationLevel.Known

If the current contact already is known, IdentifyAs() will not merge it with an existing contact that already has the identifier.

So what we ended up doing was this:

public bool IdentifyAs(string source, string identifier)
{
    if (Tracker.Current == null)
    {
        return false;
    }

    // Contact already has the identifier
    if (Tracker.Current.Session.Contact.Identifiers.Any(x => x.Source == source && x.Identifier == identifier))
    {
        return true;
    }

    var manager = Sitecore.Configuration.Factory.CreateObject("tracking/contactManager", true) as Sitecore.Analytics.Tracking.ContactManager;

    if (manager == null)
    {
        Log.Error("XConnectContactRepository: Unable to instantiate ContactManager", this);
        return false;
    }

    // Use default identifyAs for unknown contacts
    if (Tracker.Current.Contact.IdentificationLevel != ContactIdentificationLevel.Known)
    {
        Tracker.Current.Session.IdentifyAs(source, identifier);

        var contactId = Tracker.Current.Contact.ContactId;
        manager.RemoveFromSession(contactId);
        Tracker.Current.Session.Contact = manager.LoadContact(contactId);
        return true;
    }

    var existingContact = manager.LoadContact(source, identifier);

    // No other contact has this identifier yet: just set it
    if (existingContact == null)
    {
        var contactId = Tracker.Current.Session.Contact.ContactId;

        Log.Info($"Add identifier for contact '{contactId}'. {source} > {identifier}", this);

        manager.AddIdentifier(contactId, new ContactIdentifier(source, identifier, ContactIdentificationLevel.Known));
        manager.RemoveFromSession(contactId);
        Tracker.Current.Session.Contact = manager.LoadContact(contactId);

        return true;
    }

    // Other contact with identifier exists: Merge explicitly
    var currentContact = Tracker.Current.Session.Contact;
    var hasBehaviourProfiles = currentContact.BehaviorProfiles.Count != 0;

    Log.Info($"Merge contacts '{currentContact.ContactId}' into {existingContact.ContactId}. reason: {source} > {identifier}", this);

    Tracker.Current.Session.Contact = manager.MergeContacts(existingContact, currentContact);

    manager.RemoveFromSession(Tracker.Current.Contact.ContactId);

    Tracker.Current.Session.Interaction.ContactId = Tracker.Current.Session.Contact.ContactId;
    Tracker.Current.Session.Interaction.ContactVisitIndex = Tracker.Current.Session.Contact.System.VisitCount;

    if (hasBehaviourProfiles || Tracker.Current.Interaction.Profiles.GetProfileNames().Length == 0)
    {
        InitializeInteractionProfilePipeline.Run(new InitializeInteractionProfileArgs(Tracker.Current.Session));
    }

    return true;
}

We can now safely set multiple identifiers through our IdentifyAs():

IdentifyAs("USERID_SOURCE", "U1542658"); 
IdentifyAs("EMAIL_SOURCE", "[email protected]");

Update: Beware that this can lead to long contact merge chains which can impact performance. I would advise to use just one identifier if possible i.E. the E-Mail.

2

I finally got around to doing this. Once you are identified once, from that point forward you need to add identifiers manually.

First you want to check if the identifier exists already. NOTE: This code only checks the current user. There is still a risk that someone else will have the identifier in xConnect. We will need to do a lookup in xConnect for that.

public static bool DoesUserHaveEmailIdentifier()
{
    return Sitecore.Analytics.Tracker.Current.Contact.Identifiers.Any(x => x.Source == "twitter");
}

Then with the ContactManager class you can add an identifier to the current contact. Finally you need to flush out the current contact and reload it. Like the Sitecore doco states:

This identifier will not be available in Sitecore.Analytics.Tracker.Current.Contact.Identifiers, as the tracker does not reload a contact after AddIdentifier() is called.

{
    // create a new contact manager for this contact
    var contactManager = Factory.CreateObject("tracking/contactManager", true) as ContactManager;

    // add the new identifier
    var identifier = new Sitecore.Analytics.Model.Entities.ContactIdentifier("twitter", "CoolTwitterName", ContactIdentificationLevel.Known);
    contactManager.AddIdentifier("twitter", "CoolTwitterName");

    // reload the contact
    contactManager.RemoveFromSession(Tracker.Current.Contact.ContactId);
    Tracker.Current.Session.Contact = contactManager.LoadContact(Tracker.Current.Session.Contact.ContactId);
}
2
  • 1
    Beware, this will not handle merging if a contact already exists with the same identifier. We ended up having to trigger merging when that was the case.
    – Mark Lowe
    Commented May 8, 2019 at 16:30
  • Good point @MarkLowe. I think in his case he wants to assign both identifiers at the same time. I don't think merging is an issue in that scenario.
    – Chris Auer
    Commented May 8, 2019 at 18:30

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.