User Object
Every assignment in ABetterChoice is tied to a user object. The user object carries two pieces of information:
- a unit ID that decides which experiment group the call lands in;
- optional attributes that decide which audience targeting rules the call satisfies.
This page describes how to build a user object correctly across SDKs and the HTTP API.
The Go and HTTP code paths below are generally available today. The iOS, Android, JavaScript, and C++ snippets are a shape preview — those SDKs are tagged
Coming soonunderSettings → SDK&Key.
Unit ID
A unit ID is a stable string that identifies the unit of randomization for your experiments. The platform always assigns the same unit ID to the same group for the life of an experiment.
| Use this kind of ID | When |
|---|---|
| User ID | The experiment compares logged-in users; you have a stable internal ID. |
| Session ID | Pre-login flows where a user ID does not exist yet. |
| Device / install ID | Mobile apps where you want to keep assignments tied to the install. |
Build the unit ID once, server-side or at first launch, and reuse it. Avoid concatenating PII into the unit ID (user@example.com:1) — it leaks into exposure logs.
ctx := abc.NewUserContext("user_id_1") // GoexpOptions.unitId = @"user_id_1"; // iOSabc.init({ projectId, unitId: "user_id_1", ... }) // JavaScriptSwitching unit ID
Client SDKs support switchUnitId for cases where the same app session sees a different unit later (the user logs in, switches account, etc.). The SDK re-fetches assignments for the new unit:
mAbcExpSDK.switchUnitId("otherUnitID", listener); // Androidabc.switchUnitId("other_unit_id"); // JavaScriptServer SDKs do not need a switch call — every request can construct its own user context, so the unit ID changes naturally per request.
Attributes (profiles)
Attributes let an experiment or feature flag target a subset of units (for example country == "US" AND app_version >= 1.3.0). Build the attribute set on the call site, the SDK or HTTP request forwards it:
ctx := abc.NewUserContextWithAttrs("user_id_1", map[string]string{
"country": "US",
"app_version": "1.3.0",
})abc.init({
projectId, unitId, secretKey,
attributes: { country: "US", app_version: "1.3.0" },
});For HTTP API calls, attributes go into the profiles map on the request body:
{
"project_id": "6666",
"unit_id": "user_id_1",
"profiles": { "country": { "user_attrs": ["US"] }, "age": { "user_attrs": ["18"] } }
}Built-in attributes today include country, app_version, media_source, os_platform, ram_total, first_install_version, time_since_join, and user_type. Custom attributes are created in the console under Audiences → Attributes — see Audience.
Attribute types
| Type | Console label | Comparison |
|---|---|---|
| String | String | Equality, IN, NOT IN, regex. |
| Number | Number | Equality, range, IN, NOT IN. |
| Version | Version | Semantic version compare (>=, <, =). |
The HTTP API accepts attribute values as strings only — convert numbers and booleans to strings before sending ("18", "true").
Sticky assignment
The platform hashes (unit_id, layer_or_experiment_seed) to decide the group. The hash is deterministic, so:
- the same unit ID always lands in the same group as long as the experiment's traffic allocation and salt are unchanged;
- adding or removing other experiments in the same project does not move the unit ID's group in this experiment;
- changing the layer's
% of global trafficcan move units across the included / excluded boundary — covered in Layers.