@dazn/acc-user-segmentation
v1.1.1
Published
User segmentation and percentage rollout utilities
Maintainers
Keywords
Readme
acc-user-segmentation
User segmentation and percentage rollout utilities for @dazn services.
Installation
npm install @dazn/acc-user-segmentation
# or
yarn add @dazn/acc-user-segmentationFunctions
isUserInRollout
Determines whether a user falls within a rollout percentage for a given experiment. Uses deterministic SHA-256 bucket hashing — the same user always gets the same result.
isUserInRollout(userId: string, percentage: number, experimentName?: string): boolean| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| userId | string | ✅ | — | Unique user identifier (e.g. daznId) |
| percentage | number | ✅ | — | Rollout percentage, 0–100 inclusive |
| experimentName | string | ❌ | "acc-segmentation" | Stable experiment name to namespace the bucket |
Returns: boolean — true if the user is in the rollout, false otherwise.
Throws: if percentage is not a finite number between 0 and 100.
// Using default experiment name
isUserInRollout("user-123", 10) // → true/false (deterministic)
// Using a custom experiment name
isUserInRollout("user-123", 10, "prewarm-core-call")getRolloutBucket
Returns the bucket number (1–100) a user is assigned to for a given experiment. Useful for logging alongside rollout decisions.
getRolloutBucket(userId: string, experimentName?: string): number| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| userId | string | ✅ | — | Unique user identifier |
| experimentName | string | ❌ | "acc-segmentation" | Stable experiment name |
Returns: number — bucket between 1 and 100 (inclusive).
Throws: if userId or experimentName is an empty string.
getRolloutBucket("user-123") // → e.g. 42
getRolloutBucket("user-123", "prewarm-core-call") // → e.g. 17parseRegionRolloutPercent
Parses a JSON string of region-to-percent mappings into a Map. Designed to consume values produced by Terraform's jsonencode on a map(number) variable.
parseRegionRolloutPercent(envValue: string): Map<string, number>| Parameter | Type | Required | Description |
|---|---|---|---|
| envValue | string | ✅ | JSON string e.g. '{"de":10,"at":5}' |
Returns: Map<string, number> — keys are lowercase region codes, values are percentages. Returns an empty map if the input is empty or malformed JSON (all regions default to 0%).
parseRegionRolloutPercent('{"de":10,"at":5,"ch":1}')
// → Map { "de" => 10, "at" => 5, "ch" => 1 }
parseRegionRolloutPercent("") // → Map {} (0% everywhere)
parseRegionRolloutPercent("bad") // → Map {} (malformed JSON, no throw)Terraform usage:
variable "core_rollout_percent_by_region" {
type = map(number)
default = {}
}
# In ECS task definition env vars:
value = jsonencode(var.core_rollout_percent_by_region)
# → '{"at":1,"ch":1,"de":1}'getRegionRolloutPercent
Looks up the rollout percentage for a given region from a parsed map. Returns 0 if the region is not found.
getRegionRolloutPercent(region: string, regionMap: Map<string, number>): number| Parameter | Type | Required | Description |
|---|---|---|---|
| region | string | ✅ | Region code (case-insensitive, e.g. "de", "US") |
| regionMap | Map<string, number> | ✅ | Map produced by parseRegionRolloutPercent |
Returns: number — rollout percent for the region, or 0 if not in the map.
const map = parseRegionRolloutPercent('{"de":10,"at":5}')
getRegionRolloutPercent("de", map) // → 10
getRegionRolloutPercent("DE", map) // → 10 (case-insensitive)
getRegionRolloutPercent("in", map) // → 0 (not in map → excluded from rollout)Full Example
import {
parseRegionRolloutPercent,
getRegionRolloutPercent,
getRolloutBucket,
isUserInRollout,
} from "@dazn/acc-user-segmentation";
// Parse once at module load from env var (set via Terraform jsonencode)
const ROLLOUT_MAP = parseRegionRolloutPercent(
process.env.CORE_ROLLOUT_PERCENT_BY_REGION ?? "",
);
function shouldCallCoreService(daznId: string, region: string): boolean {
const rolloutPercent = getRegionRolloutPercent(region, ROLLOUT_MAP);
const bucket = getRolloutBucket(daznId, "my-experiment");
const inRollout = isUserInRollout(daznId, rolloutPercent, "my-experiment");
console.log(`daznId=${daznId} region=${region} bucket=${bucket} percent=${rolloutPercent} inRollout=${inRollout}`);
return inRollout;
}How bucketing works
- Input
"userId:experimentName"is hashed with SHA-256 - First 8 hex characters are parsed as a 32-bit integer
(int % 100) + 1gives a deterministic bucket between 1–100- User is in rollout if
bucket <= Math.floor(percentage)
This means:
percentage = 0→ no one is includedpercentage = 100→ everyone is includedpercentage = 10→ buckets 1–10 are included (≈10% of users)- Same
userId + experimentNamealways maps to the same bucket across all services and deployments
