happy-mechanic-46342
01/09/2025, 8:17 PMfresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 8:26 PMfresh-football-47124
fresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 8:38 PMfunction main() {
// Helper aggregation functions
const sum = (arr) => arr.reduce((sum, x) => sum + x, 0);
const count = (arr) => arr.length;
const countDistinct = (arr) => new Set(arr).size;
const min = (arr) => Math.min(...arr);
const max = (arr) => Math.max(...arr);
const avg = (arr) => count(arr)>0?(sum(arr)/count(arr)):0;
const percentile = (arr, p) => {
const s = [...arr].sort((a,b)=>a-b);
if(!s.length) return 0;
if(p<=0) return s[0];
if(p>=100) return s[arr.length-1];
const r = (s.length-1)*p/100;
const rf = Math.ceil(r) - r;
return s[Math.floor(r)]*rf + s[Math.ceil(r)]*(1-rf);
};
const median = (arr) => percentile(arr, 50);
// Experiment exposure event
function isExposureEvent(event) {
return event.name === "experiment_started" && event.properties["name"] === "bng-direct-domain-cta" && event.time >= 1734722640000 && event.time <= 1736454681475;
}
// domains_searched
function isMetric0(event) {
return event.name === "domains_searched";
}
// Domains purchased
function isMetric1(event) {
return event.name === "product_purchased" && event.properties["item_name"]+'' == "Domain Plan";
}
// Signups
function isMetric2(event) {
return event.name === "signup";
}
// Purchases Total - 72 hours
function isMetric3(event) {
return event.name === "product_purchased";
}
return Events({
"from_date": "2024-12-20",
"to_date": "2025-01-09",
"event_selectors": [
{
"event": "domains_searched"
},
{
"event": "product_purchased"
},
{
"event": "signup"
},
{
"event": "experiment_started"
}
]
})
.filter(function(event) {
// Experiment exposure event
if(isExposureEvent(event)) return true;
// domains_searched
if(isMetric0(event)) return true;
// Domains purchased
if(isMetric1(event)) return true;
// Signups
if(isMetric2(event)) return true;
// Purchases Total - 72 hours
if(isMetric3(event)) return true;
// Otherwise, ignore the event
return false;
})
// Array of metric values for each user
.groupByUser(function(state, events) {
state = state || {
inExperiment: false,
multipleVariants: false,
start: null,
variation: null,
m0: [],
m1: [],
m2: [],
m3: [],
};
for(var i=0; i<events.length; i++) {
const event = events[i];
// User is put into the experiment
if(isExposureEvent(event)) {
if(!state.inExperiment) {
state.inExperiment = true;
state.variation = event.properties["variant"];
state.start = event.time;
continue;
}
else if(state.variation !== event.properties["variant"]) {
state.multipleVariants = true;
continue;
}
else {
continue;
}
}
// Not in the experiment yet
if(!state.inExperiment) {
continue;
}
// Saw multiple variants so ignore
if(state.multipleVariants) {
continue;
}
// Metric - domains_searched
if(isMetric0(event) && event.time - state.start < 21600000) {
state.m0.push(1);
}
// Metric - Domains purchased
if(isMetric1(event) && event.time - state.start < 259200000) {
state.m1.push(1);
}
// Metric - Signups
if(isMetric2(event) && event.time - state.start < 21600000) {
state.m2.push(1);
}
// Metric - Purchases Total - 72 hours
if(isMetric3(event) && event.time - state.start < 259200000) {
state.m3.push(1);
}
}
return state;
})
// Remove users that are not in the experiment
.filter(function(ev) {
if(!ev.value.inExperiment) return false;
if(ev.value.multipleVariants) return false;
if(ev.value.variation === null || ev.value.variation === undefined) return false;
return true;
})
// Aggregate the metric value arrays for each user
.map(function(user) {
// Metric - domains_searched
user.value.m0 = user.value.m0.length ? 1 : 0;
// Metric - Domains purchased
user.value.m1 = user.value.m1.length ? 1 : 0;
// Metric - Signups
user.value.m2 = user.value.m2.length ? 1 : 0;
// Metric - Purchases Total - 72 hours
user.value.m3 = user.value.m3.length ? 1 : 0;
return user;
})
// One group per experiment variation with summary data
.groupBy(["value.variation"], [
// Total users in the group
mixpanel.reducer.count(),
// Metric - domains_searched
mixpanel.reducer.numeric_summary('value.m0'),
// Metric - Domains purchased
mixpanel.reducer.numeric_summary('value.m1'),
// Metric - Signups
mixpanel.reducer.numeric_summary('value.m2'),
// Metric - Purchases Total - 72 hours
mixpanel.reducer.numeric_summary('value.m3'),
])
// Convert to an object that's easier to work with
.map(row => {
const ret = {
variation: row.key[0],
dimension: '',
users: row.value[0],
metrics: [],
};
const metricIds = [
// domains_searched
"met_19g61slntdyng5",
// Domains purchased
"met_19g61olskz2kr1",
// Signups
"met_19g61plncf38yt",
// Purchases Total - 72 hours
"met_19g62clzrcsatb"
];
const metricTypes = [
"binomial","binomial","binomial","binomial"
];
for(let i=1; i<row.value.length; i++) {
ret.metrics.push({
id: metricIds[i-1],
metric_type: metricTypes[i-1],
count: row.value[i].count,
main_sum: row.value[i].sum,
main_sum_squares: row.value[i].sum_squares,
});
}
return ret;
});
}
happy-mechanic-46342
01/09/2025, 8:38 PMhappy-mechanic-46342
01/09/2025, 8:45 PMhappy-mechanic-46342
01/09/2025, 8:47 PMtrackingCallback
to mixpanel only fires when I am authed, and I can get assigned variants when unauthed for one experiment and for another another experiment I cant get assigned to a variant that has 99% split(skewed for testing)fresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 8:50 PMfresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 10:06 PMfresh-football-47124
happy-mechanic-46342
01/09/2025, 10:07 PMfresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 10:09 PMtrackingCallback
to mixpanel stops working for unauthed users thus we are not getting any data for experiments that are intended to run outside of auth wall.fresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 10:11 PMfresh-football-47124
fresh-football-47124
happy-mechanic-46342
01/09/2025, 10:11 PM