Targeting Users and Controlling Assignments
Not every experiment should run for every user. Sometimes you want to target specific browsers, geographies, or user segments. Other times you need to override which variant a user sees for development, QA, or API-driven personalization.
This page covers three related features. Jump to the one you need:
- Attributes - pass user metadata so you can create audience segments in the Web Console
- Custom assignments - programmatically choose which variant a user sees (counted as real data)
- Overrides - force a variant for testing without affecting experiment statistics
Custom assignments are counted as real experiment data. Use them when an external system (ML model, third-party targeting) decides the variant and you want those users in your analysis. Overrides are ignored by the statistics engine. Use them for development and QA.
Passing user attributes for targeting
Attributes are metadata about the user or request. Once you pass them to the SDK, you can use them in the Web Console to create audience segments that control who enters an experiment.
A common example: you're running an experiment only for mobile users. Pass the
user_agent attribute and the SDK will automatically parse it into browser, OS, and
device attributes that you can filter on in the Web Console.
Other useful attributes might include:
- Geographic data like country or region
- Account properties like subscription tier or account age
- Request metadata like referrer or landing page
Set attributes using the attribute() or attributes() methods, before or
after the context is ready.
A particularly useful attribute is user_agent. When you pass it to the SDK,
ABsmartly automatically parses it into browser, OS, and device attributes that
you can use for targeting in the Web Console. See
Segments in Dashboard Settings
for details.
- Javascript
- Python3
- React
- Swift
- Vue2
- Vue3
- Java
- Go
- .NET
- PHP
- Ruby
- Flutter/Dart
context.attribute("user_agent", navigator.userAgent);
context.attributes({
customer_time:
user.created > new Date().getTime() - 24 * 60 * 60 * 1000
? "new_customer"
: "returning_customer",
user_type: user.isInternal ? "internal" : "normal",
url: location.toString(),
user_agent: navigator.userAgent,
referrer: document.referrer,
screenName,
pageName,
country: headers["HTTP_CF_IPCOUNTRY"],
language: headers["Accept-Language"],
channel: query_params.utm_medium,
});
context.set_attribute("user_agent", req.get_header("User-Agent"))
context.set_attributes({
"customer_age": "new_customer"
})
The context can be used directly to set attributes, like so:
const { context } = useABSmartly();
context.attributes({
customer_time:
user.created > new Date().getTime() - 24 * 60 * 60 * 1000
? "new_customer"
: "returning_customer",
user_type: user.isInternal ? "internal" : "normal",
url: location.toString(),
user_agent: navigator.userAgent,
referrer: document.referrer,
screenName,
pageName,
country: headers["HTTP_CF_IPCOUNTRY"],
language: headers["Accept-Language"],
channel: query_params.utm_medium,
});
Or you can pass them as a prop to the Treatment or TreatmentFunction components.
<Treatment
attributes={{
customer_time:
user.created > new Date().getTime() - 24 * 60 * 60 * 1000
? "new_customer"
: "returning_customer",
user_type: user.isInternal ? "internal" : "normal",
url: location.toString(),
user_agent: navigator.userAgent,
// ... any other attributes you want to set
}}>
<TreatmentVariant variant={0}>
<h1>Variant 0</h1>
</TreatmentVariant>
<TreatmentVariant variant={1}>
<h1>Variant 1</h1>
</TreatmentVariant>
</Treatment>
The attribute() and attributes() methods can be called inside or outside
of a useEffect.
context.setAttribute(name: "device", value: UIDevice.current.model)
context.setAttributes(["customer_age": "new_customer", "screen": "product"])
Attributes can be set in script.
this.$absmartly.attribute("user_agent", navigator.userAgent);
this.$absmartly.attributes({
customer_age: "new_customer",
});
Or directly in templates with the :attributes property of the Treatment
component.
<treatment
name="exp_test_experiment"
:attributes="{ customer_age: 'returning' }"
>
<template #default="{ config, treatment, ready }">
<template v-if="ready">
<my-button v-if="treatment == 0"></my-button>
<my-button v-else-if="treatment == 1" :color="config.color"></my-button>
<my-other-button
v-else-if="treatment == 2"
:color="config.color"
></my-other-button>
</template>
<template v-else><my-spinner></my-spinner></template>
</template>
</treatment>
Attributes can be set in script.
this.$absmartly.attribute("user_agent", navigator.userAgent);
this.$absmartly.attributes({
customer_age: "new_customer",
});
Or directly in templates with the :attributes property of the Treatment
component.
<treatment
name="exp_test_experiment"
:attributes="{ customer_age: 'returning' }"
>
<template #default="{ config, treatment, ready }">
<template v-if="ready">
<my-button v-if="treatment == 0"></my-button>
<my-button v-else-if="treatment == 1" :color="config.color"></my-button>
<my-other-button
v-else-if="treatment == 2"
:color="config.color"
></my-other-button>
</template>
<template v-else><my-spinner></my-spinner></template>
</template>
</treatment>
context.setAttribute('user_agent', req.getHeader("User-Agent"));
context.setAttributes(Map.of(
"customer_age", "new_customer"
));
context.SetAttribute("user_agent", req.GetHeader("User-Agent"));
context.SetAttributes(map[string]string{
"customer_age": "new_customer",
}
context.SetAttribute('user_agent', Request.Headers["User-Agent"]);
context.SetAttributes(new Dictionary<string, object>() {
{ "customer_age", "new_customer" }
});
$context->setAttribute('session_id', \session_id());
$context->setAttributes(
[
'customer_age' => 'new_customer'
]
);
context.set_attribute('session_id', session_id)
context.set_attributes(
'customer_age' => 'new_customer'
)
context.setAttribute("attribute", 1);
context.setAttributes(
{
"attribute": 1,
},
);
You should create audiences with the same attributes as those in the Web Console.
By default it will not enforce these conditions, but if for some reason the
treatment() method is called for a user that doesn’t meet the correct criteria, the
Web Console will warn you about it.
Custom assignments
Sometimes you need to control which variant a user gets based on external logic. Maybe your recommendation engine determines the best variant, or you're integrating with a third-party targeting system that provides variant selections.
Custom assignments let you do this. A few real scenarios:
- ML-driven variant selection. Your model predicts which variant performs best for each user segment, and you feed that into ABsmartly.
- Third-party targeting integration. An external system decides the allocation, and you pass it through to ABsmartly for tracking.
- Geography-based logic. An API call determines the user's region, and you assign variants accordingly.
Custom assignments are counted as real experiment data. ABsmartly's statistics engine will include these users in the analysis. If you just need to force a variant for development or QA, use overrides instead.
Set a variant for a single experiment, or use the batch method for multiple experiments at once. Both can be called before or after the context is ready.
- Javascript
- Python3
- React
- Swift
- Vue2
- Vue3
- Java
- Go
- .NET
- PHP
- Ruby
- Flutter/Dart
const chosenVariant = 1;
context.customAssignment("experiment_name", chosenVariant);
For multiple experiments:
const assignments = {
experiment_name: 1,
another_experiment_name: 0,
a_third_experiment_name: 2,
};
context.customAssignments(assignments);
context.set_custom_assignment("exp_test_not_eligible", 3)
For multiple experiments:
context.set_custom_assignments({"db_user_id2": 1})
const { context } = useABSmartly();
const chosenVariant = 1;
context.customAssignment("experiment_name", chosenVariant);
For multiple experiments:
const { context } = useABSmartly();
const assignments = {
experiment_name: 1,
another_experiment_name: 0,
a_third_experiment_name: 2,
};
context.customAssignments(assignments);
let chosenVariant = 1
context.setCustomAssignment("experiment_name", chosenVariant)
For multiple experiments:
let assignments = ["experiment_name": 1,
"another_experiment_name": 0,
"a_third_experiment_name": 2]
context.setCustomAssignments(assignments)
const chosenVariant = 1;
this.$absmartly.customAssignment("experiment_name", chosenVariant);
For multiple experiments:
const assignments = {
experiment_name: 1,
another_experiment_name: 0,
a_third_experiment_name: 2,
};
this.$absmartly.customAssignments(assignments);
const chosenVariant = 1;
this.$absmartly.customAssignment("experiment_name", chosenVariant);
For multiple experiments:
const assignments = {
experiment_name: 1,
another_experiment_name: 0,
a_third_experiment_name: 2,
};
this.$absmartly.customAssignments(assignments);
final int chosenVariant = 1;
context.setCustomAssignment("experiment_name", chosenVariant);
For multiple experiments:
final Map<String, Integer> assignments = Map.of(
"experiment_name", 1,
"another_experiment_name", 0,
"a_third_experiment_name", 2,
)
context.setCustomAssignments(assignments);
var chosenVariant = 1;
context.SetCustomAssignment("experiment_name", chosenVariant);
For multiple experiments:
var assignments = map[string]int{
"experiment_name": 1,
"another_experiment_name": 0,
"a_third_experiment_name": 2,
}
context.SetCustomAssignments(assignments)
var chosenVariant = 1;
context.SetCustomAssignment("experiment_name", chosenVariant);
For multiple experiments:
var assignments = new Dictionary<string,int>(){
{"experiment_name", 1},
{"another_experiment_name", 0},
{"a_third_experiment_name", 2}
}
context.SetCustomAssignments(assignments)
$chosenVariant = 1;
$context->setCustomAssignment("experiment_name", $chosenVariant);
For multiple experiments:
$assignments = [
"experiment_name" => 1,
"another_experiment_name" => 0,
"a_third_experiment_name" => 2
];
$context->setCustomAssignments($assignments);
chosen_variant = 1
context.set_custom_assignment('experiment_name', chosen_variant)
For multiple experiments:
assignments = [
'experiment_name' => 1,
'another_experiment_name' => 0,
'a_third_experiment_name' => 2
]
context.set_custom_assignments(assignments)
context.setCustomAssignment("experimentName", 1);
For multiple experiments:
context.setCustomAssignments({"experimentName": 1});
Events with custom assignments are counted as eligible events by the ABsmartly statistics engines. If you are using these methods for development purposes (to force a particular variant for yourself or somebody else on the team) you probably need overrides instead.
Overriding variants for development and QA
During development and QA, you need to see specific variants without polluting your experiment data. Overrides solve this. They force a particular variant for a user, but the event is marked as ineligible and completely ignored by ABsmartly's statistics engine.
Use overrides when:
- You're developing a new variant and need to see it in your local environment
- QA is testing each variant before the experiment goes live
- A stakeholder wants a demo of a specific variant
Overridden events are marked as ineligible and completely ignored by ABsmartly's statistics engine. If you need the event to count as real data, use custom assignments instead, though this is rarely what you want for QA.
Override methods force a specific variant. They can be called before the context is ready.
- Javascript
- Python3
- React
- Swift
- Vue2
- Vue3
- Java
- Go
- .NET
- PHP
- Ruby
- Flutter/Dart
context.override("exp_test_experiment", 1); // force variant 1 of treatment
context.overrides({
exp_test_experiment: 1,
exp_another_experiment: 0,
});
context.set_override("exp_test_experiment", 1) # force variant 1 of treatment
context.set_overrides({
"exp_test_experiment": 1,
"exp_another_experiment": 0
})
const { context } = useABSmartly();
context.override("exp_test_experiment", 1); // force variant 1 of treatment
context.overrides({
exp_test_experiment: 1,
exp_another_experiment: 0,
});
context.setOverride(experimentName: "exp_test_experiment", variant: 1) // force variant 1 of treatment
context.setOverrides(["exp_test_experiment": 1, "exp_another_experiment": 0])
In the SDK initialization
Vue.use(absmartly.ABSmartlyVue, {
sdkOptions: {
/* ... */
},
context: {
/* ... */
},
overrides: {
exp_test_development: 1,
},
});
With the override methods
this.$absmartly.override("exp_test_experiment", 1); // force variant 1 of treatment
this.$absmartly.overrides({
exp_test_experiment: 1,
exp_another_experiment: 0,
});
In the SDK initialization
Vue.use(absmartly.ABSmartlyVue, {
sdkOptions: {
/* ... */
},
context: {
/* ... */
},
overrides: {
exp_test_development: 1,
},
});
With the override methods
this.$absmartly.override("exp_test_experiment", 1); // force variant 1 of treatment
this.$absmartly.overrides({
exp_test_experiment: 1,
exp_another_experiment: 0,
});
context.setOverride("exp_test_experiment", 1); // force variant 1 of treatment
context.setOverrides(Map.of(
"exp_test_experiment", 1,
"exp_another_experiment", 0
));
context.SetOverride("exp_test_experiment", 1) // force variant 1 of treatment
context.SetOverrides(map[string]int{
"exp_test_experiment": 1,
"exp_another_experiment": 0
})
context.SetOverride("exp_test_experiment", 1); // force variant 1 of treatment
context.SetOverrides(new Dictionary<string, int>() {
{ "exp_test_experiment", 1 },
{ "exp_another_experiment", 0 }
});
$context->setOverride("exp_test_experiment", 1); // force variant 1 of treatment
$context->setOverrides(
[
'exp_test_experiment' => 1,
'exp_another_experiment' => 0,
]
);
context.set_override("exp_test_experiment", 1) # force variant 1 of treatment
context.set_overrides(
'exp_test_experiment' => 1,
'exp_another_experiment' => 0,
)
context.setOverride(experimentName, variant)
context.setOverrides({
"exp_test_experiment": 1,
"exp_another_experiment": 0,
});
Overriding Based On URL Params
The most common use case for overriding is to override a treatment based on
params in the URL. This allows for greater flexibility in the development and
QA stages. The following Javascript function can be ported to any language and
used to parse the URL query parameters and return an object of overrides. This
object can then be passed to the overrides() context method to force a particular
variant for one or multiple experiment(s).
Here we using absmartly_ as a prefix for the query parameters, but you can
use whatever prefix you like. It could be exp_, test_, or even a simple _!
function getABsmartlyOverridesFromQuery(req) {
const overrides = {};
// Iterate through all query parameters
for (const [key, value] of Object.entries(req.query)) {
// Check if the query parameter starts with "absmartly_"
if (key.startsWith('absmartly_')) {
// Extract the experiment name (remove "absmartly_" prefix)
const experimentName = key.slice('absmartly_'.length);
// Convert the value to a number if possible, otherwise keep it as a string
const variantValue = isNaN(value) ? value : Number(value);
// Add to overrides object
overrides[experimentName] = variantValue;
}
}
return overrides;
}