The thing is, I'm using a middleware for A/B testi...
# ask-questions
b
The thing is, I'm using a middleware for A/B testing, and I'm not exactly sure how to get the Mixpanel distinct id in this middleware, or even if I can access it.
f
Hi Cezar
let me find you my sample code for Mixpanel...
Copy code
mixpanel.init('6a37b4557......[replace]', {
    debug: true,
    loaded: function(mx) {
        growthbook.setAttributes({
            ...growthbook.getAttributes(),
            id: mx.get_distinct_id()
        });
    }
});
b
Here's what I've got.
I'm initializing the Mixpanel lib (using the
mixpanel-browser
package) in the
_app.js
file.
which, I think is already too late...
f
you can update the attributes with setAttributes (which replaces all the attributes)
Did you try that sample code?
b
oh, so if I do this in
_app.js
...
Copy code
const growthbook = new GrowthBook({
    attributes: { id: visitor_id },
    features: await getFeatures(),
    trackingCallback: (experiment, result) => {
      mixpanel.track("$experiment_started", {
        "Experiment name": experiment.key,
        "Variant name": result.variationId
      });
    }
  });
I did try it, but it didn't work
f
is that the only attribute your adding?
b
well, yeah... for now... just trying to set it up
this code
Copy code
const growthbook = new GrowthBook({
    attributes: { id: visitor_id },
    features: await getFeatures(),
    trackingCallback: (experiment, result) => {
      mixpanel.track("$experiment_started", {
        "Experiment name": experiment.key,
        "Variant name": result.variationId
      });
    }
  });
gives me an error...
Copy code
TypeError: Cannot read properties of undefined (reading 'disable_all_events')
    at MixpanelLib._event_is_disabled (webpack-internal:///(middleware)/./node_modules/mixpanel-browser/dist/mixpanel.cjs.js:5561:21)
    at MixpanelLib.eval (webpack-internal:///(middleware)/./node_modules/mixpanel-browser/dist/mixpanel.cjs.js:4776:14)
    at MixpanelLib.eval [as track] (webpack-internal:///(middleware)/./node_modules/mixpanel-browser/dist/mixpanel.cjs.js:2789:27)
    at Object.trackingCallback (webpack-internal:///(middleware)/./pages/_middleware.ts:45:69)
    at GrowthBook.track (webpack-internal:///(middleware)/./node_modules/@growthbook/growthbook/dist/esm/GrowthBook.js:498:20)
    at GrowthBook._run (webpack-internal:///(middleware)/./node_modules/@growthbook/growthbook/dist/esm/GrowthBook.js:473:10)
    at GrowthBook.run (webpack-internal:///(middleware)/./node_modules/@growthbook/growthbook/dist/esm/GrowthBook.js:126:25)
    at GrowthBook.evalFeature (webpack-internal:///(middleware)/./node_modules/@growthbook/growthbook/dist/esm/GrowthBook.js:311:26)
    at GrowthBook.feature (webpack-internal:///(middleware)/./node_modules/@growthbook/growthbook/dist/esm/GrowthBook.js:220:17)
    at Object.middleware [as handler] (webpack-internal:///(middleware)/./pages/_middleware.ts:53:20)
I"m guessing the
mixpanel
object doesn't make sense in the context of a middleware?
f
could be
This is how I got it working in my NextJS app (using _app.tsx):
Copy code
const growthbook = new GrowthBook({
  trackingCallback: (experiment, result) => {
      mixpanel.track("Experiment Viewed",
          {
              'Experiment Id': experiment.key,
              'Variant Id' : result.variationId
          }
      );
  }
});

mixpanel.init('60c30...b4557', {
    debug: true,
    loaded: function(mx) {
        growthbook.setAttributes({
            ...growthbook.getAttributes(),
            id: mx.get_distinct_id()
        });
    }
});

const FEATURES_ENDPOINT = "<http://localhost:3100/api/features/key_dev_e...5365>";

function MyApp({ Component, pageProps }: AppProps) {

    useEffect(() => {
    // Load feature definitions from API
    fetch(FEATURES_ENDPOINT)
        .then((res) => res.json())
        .then((json) => {
          growthbook.setFeatures(json.features);
        });

    // TODO: replace with real targeting attributes
    growthbook.setAttributes({
      "id": "432",
      "deviceId": "foo",
      "company": "foo",
      "loggedIn": true,
      "employee": true,
      "country": "foo",
      "browser": "foo",
      "url": "foo"
    })
  }, [])

  return (
      <GrowthBookProvider growthbook={growthbook}>
        <Component {...pageProps} />
      </GrowthBookProvider>
  )
}
But I haven't tested using the middleware
@future-teacher-7046 can help you when he's around
b
It seems Mixpanel has another package for Node, but using that I get an error as well.
Copy code
You're using a Node.js module (events) which is not supported in the Edge Runtime.
f
I can't find very much about using Mixpanel from within Next.js middleware so not sure if that's possible. I also don't think you'll be able to get the distinct id there easily.
One option is to use your own visitor id cookie for assigning variations. Then pass the result to the front end in a cookie and track it in Mixpanel when the page loads.
b
Would creating 2 instances of GrowthBook work? Like this: in the middleware
Copy code
// Get existing visitor cookie or create a new one
  let visitor_id = req.cookies[COOKIE] || crypto.randomUUID()

  const growthbook = new GrowthBook({
    attributes: { id: visitor_id },
    features: await getFeatures()
  });
and then in
_app.js
Copy code
new GrowthBook({
      attributes: { id: mixpanel_id },
      trackingCallback: (experiment, result) => {
        mixNode.track("$experiment_started", {
          "Experiment name": experiment.key,
          "Variant name": result.variationId
        });
      }
    });
f
The tracking callback only fires on the same GrowthBook instance where you evaluate a feature value.
b
oh, so it wouldn't work
One option is to use your own visitor id cookie for assigning variations. Then pass the result to the front end in a cookie and track it in Mixpanel when the page loads.
Do you have an example of this?
I can't visualize how that works.
f
In your middleware, set a cookie with the experiment key and assigned variation
Copy code
res.cookie("GB_EXPERIMENTS", JSON.stringify([{key: "my-experiment", variationId: 1}])
Then in your
_app.js
track in mixpanel:
Copy code
useEffect(() => {
  const experiments = document.cookie["GB_EXPERIMENTS")
  if (!experiments) return;
  const parsed = JSON.parse(experiments);
  if (!parsed) return;
  parsed.forEach(res => {
    mixpanel.track("$experiment_started", {
      "Experiment name": res.key,
      "Variant name": res.variationId
    })
  })
}, [])
b
Cool, that seems to work. Thank you.
147 Views