Skip to main content
Solved

Klaviyo JS creating duplicate accounts


Forum|alt.badge.img+1
  • Contributor I
  • 5 replies

We are seeing an issue where duplicate profiles are being created by Klaviyo JS.

On our site, when a user changes their email address; 

  1. On each page load, we send over an Identify call with the user’s email address
  2. The form is posted to our server with a full page refresh
  3. The server will then send an API request to Klaviyo (https://a.klaviyo.com/api/profile-import) which will upsert the profile with the new email address. 
  4. The page loads and Klaviyo instantly sends over an “Active on Site” event using the cached _ks parameter which is linked to the old email address. The profile’s email address in Klaviyo has already been updated via the API call, so Klaviyo thinks that this is a new user and created a duplicate account.
  5. A few milliseconds later, the Identify call is made with the updated email address and Klaviyo starts tracking the correct 

 

I believe this is the same issue which was experienced in this, and we’ve tried deleting Klaviyo JS’s _ks cookie on the edit profile page. This has fixed the aforementioned scenario for our testing, however, it seems some users are still experiencing it and we’re seeing duplicate accounts and 409 errors in our logs. 

 

I was wondering if anyone else has experienced this?

Does anyone know if there is a way to get Klaviyo’s JS to wait for the Identify call before sending an Active on Site event? 

Best answer by talhahussain

@Joely 

There are some suggestions i would like to apply  

  1. Ensure Identify Runs Before Events

    • First, update the user’s identity before tracking any events:
    window.klaviyo.identify({ $id: user.id, $email: user.email }); window.klaviyo.track("Active on Site"); // Fire after identify 
  2. Clear Cached Data Before Identify

    • Reset Klaviyo’s cached user info before updating:

    window.klaviyo.reset(); // Clears old data window.klaviyo.identify({ $id: user.id, $email: user.newEmail });

  3. Use Only $id First When Changing Email

    • Identify with $id first, then update $email after a delay:

    window.klaviyo.identify({ $id: user.id }); setTimeout(() => { window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); }, 500);

  4. Delay Event Tracking After Email Change

    • Wait a bit before firing events to ensure identity is updated:

    window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); setTimeout(() => { window.klaviyo.track("Active on Site"); }, 1000);

Key Takeaways

  • Reset Klaviyo JS (window.klaviyo.reset()) before updating email.
  • Use $id first, then update $email.
  • Delay event tracking to avoid race conditions.
View original
Did this topic or the replies in the thread help you find an answer to your question?

6 replies

talhahussain
Problem Solver IV
Forum|alt.badge.img+8
  • Problem Solver IV
  • 76 replies
  • February 5, 2025

@Joely  Experiencing duplicate profiles in Klaviyo often results from inconsistencies in how user identities are tracked, particularly when mixing the use of $id and $email identifiers. If some API calls identify users solely by a unique $id and others by $email, Klaviyo may create separate profiles for the same individual. To prevent this, it's recommended to consistently use email addresses as the primary identifier across all tracking methods. This approach minimizes the risk of duplicate profiles and ensures accurate user data consolidation.


Forum|alt.badge.img+1
  • Author
  • Contributor I
  • 5 replies
  • February 5, 2025

Thanks ​@talhahussain , 

In this situation Klaviyo JS is creating the additional profile when the user changes their email address. The additional (duplicate) profile has the user’s previous email and is created due to a race condition in Klaviyo JS firing off the Active on Site event with the cached user details before the Identify call is able to take place. How would you suggest I change this based on your recommendation ? 

 

If it helps, we are using $id, $email and $external_id for all API calls. We were told that we needed to use $id if the user is updating their email address. 

 

 


talhahussain
Problem Solver IV
Forum|alt.badge.img+8
  • Problem Solver IV
  • 76 replies
  • Answer
  • February 5, 2025

@Joely 

There are some suggestions i would like to apply  

  1. Ensure Identify Runs Before Events

    • First, update the user’s identity before tracking any events:
    window.klaviyo.identify({ $id: user.id, $email: user.email }); window.klaviyo.track("Active on Site"); // Fire after identify 
  2. Clear Cached Data Before Identify

    • Reset Klaviyo’s cached user info before updating:

    window.klaviyo.reset(); // Clears old data window.klaviyo.identify({ $id: user.id, $email: user.newEmail });

  3. Use Only $id First When Changing Email

    • Identify with $id first, then update $email after a delay:

    window.klaviyo.identify({ $id: user.id }); setTimeout(() => { window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); }, 500);

  4. Delay Event Tracking After Email Change

    • Wait a bit before firing events to ensure identity is updated:

    window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); setTimeout(() => { window.klaviyo.track("Active on Site"); }, 1000);

Key Takeaways

  • Reset Klaviyo JS (window.klaviyo.reset()) before updating email.
  • Use $id first, then update $email.
  • Delay event tracking to avoid race conditions.

Forum|alt.badge.img+1
  • Author
  • Contributor I
  • 5 replies
  • February 6, 2025

wow ​@talhahussain , this is extremely helpful. Thank you!!

We aren’t currently sending an “Active on Site” event manually, this is automatically sent by Klaviyo’s onsite JS when it loads. Looking through the code, it looks like the fender_analytics.js file which the Klaviyo onsite JS includes triggers this. It seems that the Active on Site event fires as soon as the Klaviyo JS loads. I was hoping they waited for a document.onload events so I could use a <script defer> tag and execute the identify call before Klaviyo fired the event. 

Your suggestion (#2) to clear the cache and then identify might engage in a bit of a race condition but it might work! I can’t seem to find any Klaviyo developer docs about the onsite JS and the “reset” function. Do you happen to know where I can find more out about this? 


talhahussain
Problem Solver IV
Forum|alt.badge.img+8
  • Problem Solver IV
  • 76 replies
  • February 6, 2025

Great discussion, everyone! @Joely, I see where the challenge comes from—Klaviyo’s JS firing the "Active on Site" event immediately on load, before the updated Identify call can take effect. That race condition makes sense, especially since the cached _ks parameter retains the old email.

Potential Solutions to Prevent Duplicate Profiles

       Manually Delay "Active on Site" Event

  • Since Klaviyo’s JS fires the event instantly, you could intercept and delay it until after Identify runs.
  • Try blocking the event temporarily, run Identify, then trigger it manually:

    window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); setTimeout(() => { window.klaviyo.track("Active on Site"); }, 1000); // Delay to ensure Identify finishes

      Force Reset Before Identify

  • If _ks is caching old data, force-reset Klaviyo's session first:

    window.klaviyo.reset(); window.klaviyo.identify({ $id: user.id, $email: user.newEmail });

      Dynamically Load Klaviyo’s JS After Identify

  • Instead of using <script defer>, dynamically load the Klaviyo JS only after Identify is done:function loadKlaviyo() { var script = document.createElement("script"); script.src = "https://static.klaviyo.com/onsite/js/klaviyo.js"; script.async = true; document.head.appendChild(script); } window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); loadKlaviyo(); // Load Klaviyo JS after Identify

Where to Find More Info?

 The Klaviyo API docs have some info on Identify and Profiles:

  • Profiles API
  • Klaviyo’s JS Documentation
    You might also find insights by inspecting Klaviyo's JS network requests in DevTools.

Forum|alt.badge.img+1
  • Author
  • Contributor I
  • 5 replies
  • February 12, 2025

Thank you ​@talhahussain ! I appreciate the thought you’ve put into this. I will let you know how I go!

 

One quesiton, when you talk about blocking the event temporarily. 

//will this code you posted block the active on site tracking? 

window.klaviyo.identify({ $id: user.id, $email: user.newEmail }); setTimeout(() => { window.klaviyo.track("Active on Site"); }, 1000); // Delay to ensure Identify finishes

//in looking through the klaviyo JS, it looks like Klaviyo.js includes fender_analytics.js which fires a track('__activity__') event which is their active on site event. I'd imagine we'd get into a race condition to see if this fires before the code you've posted?