mixpanel / mixpanel-node

A node.js API for mixpanel
http://www.mixpanel.com
MIT License
474 stars 161 forks source link

mixpanel.people.set() working sporadically #153

Open roland-batovski opened 4 years ago

roland-batovski commented 4 years ago

Hey all,

I've been trying to get a stable implementation of Mixpanel in our app for a couple of weeks now without luck. I'm running an Expo React-Native app with a server-side solution for the Mixpanel library. Our current flow is the following:

  1. User creates an account with our app and logs in
  2. User lands on Welcome page and is asked to give us permission for Push Notifications
  3. We do a call to our AWS Lambda API with the user's profile data and notification token
  4. The lambda (which hosts the Mixpanel code) fires a .track() event to indicate that the user is trying to send his notification token
  5. A .people.set() event is fired to save the user's profile data
  6. A .people.union() event is fired to save the user's notification token

The expected outcome is that we now have a User Profile and an event associated with said profile in Mixpanel. However, this only happens every now and then. More than 50% of our users have not had a Profile created, and there appears to be no distinction between those user that have successfully been saved to Mixpanel and those that have not.

Below is a transcript of the Lambda code which performs the Mixpanel calls:

let notificationToken = req.body.token != null ? req.body.token.data : '';
let userName          = req.body.userName;
let userEmail         = req.body.userEmail;
let userSub           = req.body.userSub;
console.log('adding to mixpanel ${userName}, ${userEmail}, ${userSub}, ${notificationToken}')

mixpanelClient.track('init notifications token', {distinct_id: userSub}, function(err) {if (err) console.log('err: ', err)})
mixpanelClient.people.set(userSub,
  {
    "$email": userEmail,
    "$last_login": new Date(),
    "user_name": userName,
  },
  function(err) {
    console.log('err: ', err);
  });

if(notificationToken && notificationToken != '') {
    mixpanelClient.people.union(userSub, {
      "$ios_devices": [notificationToken]
    });
  }

userSub is a unique identifier in this context.

While inspecting the Lambda CloudWatch logs, I couldn't find any errors being thrown back. I tried getting in touch with the support team at Mixpanel, but they haven't been able to offer much insight. I'd like to mention that our regular .track() events are going through and being recorded in Mixpanel, it's just the user profiles that are problematic and not always created. Any and all help is greatly appreciated!

Cheers!

amitgilad3 commented 4 years ago

i am also seeing this issue, i am trying to integrate mixpanel into my app. i tried the mixpanel client library for node but the user never gets created in mixpanel and i dont get any errors.

hope somebody reads this , i see that the issue is open with no response for quite some time

asdullahsiddique commented 3 years ago

Hey all,

I've been trying to get a stable implementation of Mixpanel in our app for a couple of weeks now without luck. I'm running an Expo React-Native app with a server-side solution for the Mixpanel library. Our current flow is the following:

  1. User creates an account with our app and logs in
  2. User lands on Welcome page and is asked to give us permission for Push Notifications
  3. We do a call to our AWS Lambda API with the user's profile data and notification token
  4. The lambda (which hosts the Mixpanel code) fires a .track() event to indicate that the user is trying to send his notification token
  5. A .people.set() event is fired to save the user's profile data
  6. A .people.union() event is fired to save the user's notification token

The expected outcome is that we now have a User Profile and an event associated with said profile in Mixpanel. However, this only happens every now and then. More than 50% of our users have not had a Profile created, and there appears to be no distinction between those user that have successfully been saved to Mixpanel and those that have not.

Below is a transcript of the Lambda code which performs the Mixpanel calls:

let notificationToken = req.body.token != null ? req.body.token.data : '';
let userName          = req.body.userName;
let userEmail         = req.body.userEmail;
let userSub           = req.body.userSub;
console.log('adding to mixpanel ${userName}, ${userEmail}, ${userSub}, ${notificationToken}')

mixpanelClient.track('init notifications token', {distinct_id: userSub}, function(err) {if (err) console.log('err: ', err)})
mixpanelClient.people.set(userSub,
  {
    "$email": userEmail,
    "$last_login": new Date(),
    "user_name": userName,
  },
  function(err) {
    console.log('err: ', err);
  });

if(notificationToken && notificationToken != '') {
    mixpanelClient.people.union(userSub, {
      "$ios_devices": [notificationToken]
    });
  }

userSub is a unique identifier in this context.

While inspecting the Lambda CloudWatch logs, I couldn't find any errors being thrown back. I tried getting in touch with the support team at Mixpanel, but they haven't been able to offer much insight. I'd like to mention that our regular .track() events are going through and being recorded in Mixpanel, it's just the user profiles that are problematic and not always created. Any and all help is greatly appreciated!

Cheers!

Have you managed to solve it? Experiencing the same behavior. Bests

velsa commented 2 years ago

A similar issue, the call to

people.set(distinct_id, { $email: user.email, userType: "internal' })

doesn't set the email or the internal key or any other key.

The only solution I found so far is to set those fields from the client (using the mixpanel-js library)

tylerzey commented 1 year ago

The only workaround I found was to send a post request (not using this library) as documented here:

https://developer.mixpanel.com/reference/profile-set

Would be great if the library was fixed

martindahlstrand commented 1 year ago

I had the a similar problem. The reason I think to mixpanel not to have sent the event is that the call mixpanel.track is asynchronous, and the lambda may be torn down before the send is completed. I used the interface which uses a callback to make sure that the mixpanel.track (or people.set) logic is finished before existing the lambda. After doing that I have seen no inconsistencies.

tylerzey commented 1 year ago

Interesting - I was awaiting via the callback both api calls. I even tested with an arbitrary wait of 3-5 seconds.

The mixpanel.track does work with the callback await. The people.set did not.

diegodleon commented 1 year ago

The problem seems to be the lambda dies before the callback completes.

This article solved it for me: https://medium.com/@mohie93/event-tracking-with-mixpanel-and-nodejs-3806638bf746

Just use Promisify to convert the MixPanel.track callback to a Promise then use await. The lambda will report the event then.

walterholohan commented 1 year ago

Hi, ive been using the callback promise solution and it works great for mixpanel.track, however when using it for mixpanel.people.set I sometimes get not callback response and the lambda times out. So stop the timeouts I have put a timeout in the promise of 2 seconds but that does not solve the problem of the mixpanel.people.set API failing to send the POST request. Has anyone else seen this? Is it something to do with the mixpanel endpoint not responding?

Here is the code I'm using

function withTimeout(millis: number, promise: Promise<any>) {
  const timeout = new Promise((_resolve, reject) => setTimeout(() => reject(`Timed out after ${millis} ms.`), millis))
  return Promise.race([promise, timeout])
}

/**
 * Due to the fact that the mixpanel library does not support promises
 * we have to wrap the identify function in a promise. Otherwise the
 * lambda function will finish before the request has been sent.
 * @param traits - The traits to identify the user with
 * @param mixpanel - The mixpanel instance
 * @param userId - The user id
 * @returns A promise that resolves when the identify request has been sent
 */
async function mixpanelAsyncIdentify({
  traits,
  mixpanel,
  userId,
}: {
  userId: string
  traits: { [key: string]: string | number | boolean | undefined }
  mixpanel: Mixpanel.Mixpanel
}) {
  return await withTimeout(
    2000,
    new Promise((resolve, reject) => {
      console.log('Identifying Mixpanel user', userId, traits)
      mixpanel.people.set(userId, traits, (err) => {
        if (err) {
          console.log('Failed to identify Mixpanel user', userId, traits)
          reject(err)
        } else {
          console.log('Identified Mixpanel user', userId, traits)
          resolve('success')
        }
      })
    }),
  )
}
walterholohan commented 1 year ago

I plan on trying to use the https://developer.mixpanel.com/reference/profile-set directly instead of using the node library

moosedrool commented 8 months ago

@walterholohan is there a drawback to using this instead of mixpanel.people.set? I'm sort of new to this, and am encountering the same issues.