const BUCKETS = 120 // multiple of 3 for correct split on 3-variant experiments const seed = '8fc40cab' // random seed, change to reallocate users function hashFNV(s, h = 0x811c9dc5) { for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24); } return h >>> 0; } function getBucket(key) { let n = hashFNV(key); return n % BUCKETS } function trackImpression(userId) { // ... } function getVariant(userId, experiment, trafficPercentage = 100, variants = 2) { const key = `${userId}-${experiment}-${seed}` const bucket = getBucket(key) for (let i = 0; i < variants; i++) { let threshold = (i + 1) * (trafficPercentage / variants / 100 * BUCKETS) if (bucket < threshold) { trackImpression(userId) return i } } return undefined // not in experiment }