Merging Users

When Sunshine Conversations determines that two separate users are actually the same person, the two users may be merged together in order to provide a more unified view of the user, and to allow the business to keep track of users more easily as they move between different channels. The purpose of this section is to describe when and how merges occur, and how your software should react to them.

When merges occur

Merges can be triggered in three ways:

Merging with an API call

If the business is able to confirm that two users in fact refer to the same person, a merge can be triggered manually by providing the IDs of the surviving and discarded user to the merge user API. See how merges work for more information about surviving and discarded users.

curl https://api.smooch.io/v1.1/apps/5963c0d619a30a2e00de36b8/appusers/merge \
     -X POST \
     -d '{"surviving": {"_id": "afa567114fdb04f5da925d6b"}, "discarded": {"_id": "decbf2d33e2940abe873fde3"}}' \
     -H 'content-type: application/json' \
     --user 'keyId:keySecret'

When manually merging users that have access to SDKs, it’s possible for users to lose access to their SDK conversations in some cases:

  • If an anonymous user is merged with an identified user, the anonymous user’s session token will be revoked, and they must be issued a JWT to continue using the SDK as the surviving user.
  • If two identified users are merged, the externalId of the discarded user can not be used to log in to the surviving user (it would instead generate a new user with the discarded externalId).
  • If two anonymous users are merged, the session token of the surviving user will be retained, and the discarded user will lose access to their conversation.
  • If the discarded user is online and has an active websocket connection at the time of the merge, they will receive the new session token and be able to continue as usual. If not, the conversation history will not be retrievable from the discarded user’s device and a new anonymous user will be created if they return on that device.

When dealing with users on SDKs, it is recommended to use SDK login wherever possible instead of the merge user API to avoid the pitfalls mentioned above.

Merging because of a channel transfer

When a user confirms their identity on a messaging channel by completing a channel transfer flow, it is possible that the confirmed identity already matches another user in your Sunshine Conversations app. If two anonymous users are confirmed to be in possession of the same messaging channel account or phone number, then those two users will be merged into one.

A channel transfer can be initiated either by the business via the Create Client API, or by the user choosing to continue their conversation on a different channel from the Web Messenger.

Example business-initiated flow

  1. A user named Alice sends a message to your business’ configured Twilio phone number, creating a user record in Sunshine Conversations associated to that phone number.
  2. Later on, Alice starts a conversation with your business through your iOS application. There are currently two user records in Sunshine Conversations, Alice on SMS (User X), and Alice on Twilio (User Y).
  3. During Alice’s conversation on iOS (User Y), she confirms to the business that she owns the phone number associated with User X, and would like to receive further updates over SMS.
  4. The business uses the Create Client API to attach the phone number to User Y.
  5. Sunshine Conversations determines that both User X and User Y share the same phone number, and decides that they should be merged into one.
  6. The users are merged together, and the conversation history is now shared between both iOS and SMS. Alice can choose to reply from either channel, and her replies will be routed to the same conversation.

Example user-initiated flow

  1. A user named Alice is using the Web Messenger on your business’ website to chat with a support agent.
  2. Alice does not want to remain at her computer for the duration of the support session, and chooses to continue her conversation on Facebook Messenger.
  3. Alice is now linked to the Messenger channel, and can send replies from either her browser session, or Facebook Messenger, and her replies will be routed to the same conversation (Conversation X).
  4. Later on, Alice returns to the business’ website from a different computer, and starts a new conversation (Conversation Y) with a support agent.
  5. Once again, Alice chooses to continue her conversation on Facebook Messenger.
  6. The Facebook Messenger account that she used in step 5 is the same account as was used in step 2, and therefore Sunshine Conversations determines that Conversation X and Conversation Y are referring to the same person, and therefore decides that they should be merged into one.
  7. The users are merged together and Alice now sees her full conversation history which is shared between both browsers, as well as Alice’s Facebook Messenger account. Alice can choose to reply from either channel, and her replies will be routed to the same conversation.

Merging because of a login event

When an anonymous user on the Web or Mobile SDKs is identified using the login method, and the identified user already exists in Sunshine Conversations (if they were previously active on a different device, for example) a merge will occur between the anonymous user and the identified user. This allows a user to start a conversation with your business anonymously before they log in (for example, while browsing your business’ website). After logging in, the user will still see the conversations they had before logging in and be able to seamlessly continue as a logged in user.

Example flow on Web Messenger

  1. A user named Alice visits your business’ website, and logs in using her existing account in your system.
  2. As a result of the authentication, the website calls the login method to identify the user with an externalId and JWT.
  3. Alice starts a conversation with your business using the Web Messenger, as her identified user (User X).
  4. Later on, Alice visits your website from a different browser, but does not choose to log in.
  5. Alice uses the Web Messenger to start a new anonymous conversation with your business, creating a new anonymous user (User Y).
  6. While conversing with a support agent, Alice decides to log in to your website to view her account settings.
  7. Your website calls the login method, and supplies the same externalId as in step 2.
  8. User X and User Y are now confirmed to be the same identified user, and Sunshine Conversations merges the two users into one.
  9. The users are merged together, and Alice is able to seamlessly continue her conversation using the Web Messenger, and is also able to view her previous conversations in the conversation list.

How merges work

Before a merge can occur between users, Sunshine Conversations must first elect a “surviving” user, which is the user that will remain once the merge is complete. The second user becomes the “discarded” user, and will eventually be deleted at the end of the merge. In the case of a merge initiated via channel transfer, the user that initiated the transfer becomes the surviving user. In the case of a merge initiated via a login event, the surviving user is the user that was created in Sunshine Conversations first. For merges manually triggered by an API call, the caller decides the surviving and discarded users.

Once a surviving user is elected, Sunshine Conversations starts the merge flow for the users and their associated conversations.

  1. The discarded user’s structured fields are merged with the surviving user.

    • In the case of a conflict, the discarded user’s structured fields take precedence.
    • In the case of the signedUpAt field, the earlier date is used.
  2. The discarded user’s custom metadata are merged with the surviving user’s.

    • In the case of a conflict, the discarded user’s custom metadata take precedence.
    • If the resulting size of the merged metadata is greater than the maximum allowed value of 4 KB, then individual metadata fields are discarded one by one until the object is within the size limit.
  3. The _id of the surviving user is retained, and the externalId of the surviving user is resolved according to the following logic:

    • If an anonymous user is being merged with an identified user, the externalId of the identified user is assigned to the surviving user.
    • If two identified users are being merged, the surviving user retains its original externalId.
    • If two anonymous users are being merged, the surviving user will also be anonymous and will not have an externalId.
  4. The clients arrays of both users are merged, filtering for duplicates. The resulting user will contain all the clients of both users.
  5. If the merge occurred as a result of a channel transfer, the relevant conversation histories are merged together, sorting the resulting conversation by message timestamp.
  6. The remaining conversations of the discarded user are transferred to the surviving user.
  7. A user:merge webhook is fired including the IDs of all surviving and discarded objects, as well as any custom metadata that were discarded as part of step 2. The reason field in the payload can be used to determine why the merge occurred.

Handling merge events as a business

When a merge occurs, Sunshine Conversations will send a user:merge event to any subscribed webhooks, to inform the business that a merge occurred. When you receive such an event, you should update any records in your own system that reference the discarded user (or its conversations) to instead reference the surviving user. If any record merging is required on your end, you should also perform that in response to this event.

In the event where user or conversation metadata were discarded as a result of a merge (in the case where the metadata would have exceeded the size limit of 4 KB), you may also want to handle this event in your system. The discarded metadata and their values can be found in the discardedMetadata or discardedConversationMetadata field of the webhook payload.