Config API
If your application already uses configuration objects to control behaviour (feature flags, theme settings, copy, layout), the Config API lets you run experiments on those config values with zero additional branching logic.
Instead of writing if treatment === 1 then color = green, you just merge your config
with experiment data and your existing config-driven code handles the rest. This means
you can set up new experiments from the Web Console without touching a single line of
application code.
The Config API is currently available in the Javascript SDK only.
What it replaces
Say your app has a config object that controls the homepage. Without the Config API, you'd branch on every experiment manually:
const config = {
hero_image: context.treatment("homepage_hero") === 1
? "http://cdn.com/hero-new.png"
: "http://cdn.com/hero-default.png",
button: {
color: context.treatment("homepage_hero") === 1 ? "green" : "blue",
cta: context.treatment("homepage_hero") === 1 ? "Start free trial" : "Learn more",
},
};
With mergeConfig(), you define your defaults and the SDK merges in the experiment
values automatically. In the Web Console, you'd set treatment variables that match
your config keys (e.g. hero_image, button.color, button.cta):
import { mergeConfig } from "@absmartly/javascript-sdk";
let config = {
hero_image: "http://cdn.com/hero-default.png",
button: {
color: "blue",
cta: "Learn more",
},
};
config = mergeConfig(context, config);
// config.button.color is now a getter that returns the experiment's value
// and calls treatment() automatically, so exposures are tracked for you
No branching logic in your code. New experiments can be set up entirely from the Web Console by adding variables that match your config keys.
How it works
The mergeConfig() function takes a context and your existing config object, and returns
a new one where any keys that match experiment variables are replaced with getters. When
those keys are accessed, the SDK automatically calls treatment() under the hood, so
exposures are tracked without you having to think about it.
If you use configuration files to change different aspects of your application, then you can use the Config API to greatly improve your workflow and save a lot of coding time.
// Import the mergeConfig function.
import { mergeConfig } from "@absmartly/javascript-sdk";
/*
Your current config might be something like:
const myAppConfig = { ... };
or
const myAppConfig = getConfigFromFile(config.json);
then you just need to add the mergeConfig function like this:
*/
const myAppConfig = mergeConfig(getConfigFromFile(config.json));
Basic Example
Let's say you use a configuration file to change various parameters in your application:
let cfg = {
button: {
color: "blue",
cta: "Click me",
},
hero_image: "http://cdn.com/img1.png",
some_other_stuff: {
/* ... */
},
};
Then you could use the Config API to run experiments that change those parameters.
Imagine you start two experiments:
- button_color
- Control group variables =
{ button.color: "blue" } - Variant 1 variables =
{ button.color: "green" }
- Control group variables =
- homepage_cta
- Control group variables =
{ button.cta: "Click me", hero_image: "https://cdn.com/img1.png" } - Variant 1 Variables =
{ button.cta: "Click here", hero_image: "https://cdn.com/img2.jpg" }
- Control group variables =
For each user the SDK receives a payload similar to this:
{
"guid": "dhsUiLJ7xgQBEbivw_0cjiKo9O6UlnSg",
"units": [],
"assignments": [
{
"name": "button_color",
"variant": 1,
"config": {
"button.color": "green"
}
},
{
"name": "homepage_cta",
"variant": 0,
"config": {
"button.cta": "Click me",
"hero_image": "https://cdn.com/img1.png"
}
}
]
}
This user is in Variant 1 of the button_color experiment and in the
control group for the homepage_cta experiment. Calling
context.mergeConfig(cfg) from the Javascript SDK would return a config
object like this:
{
button: {
get color: () => { context.treatment("button_color"); return "green"; },
get cta: () => { context.treatment("homepage_cta"); return "Click here"; },
}
get hero_image: () => { context.treatment("homepage_cta"); return "http://cdn.com/img1.png"; },
some_other_stuff: { /* ... */ },
}
When the config API is used, you don't need to call the treatment() method.
It will be called automatically when keys from the config are used.
So you can continue using your configuration file as you were before, but now, the correct experiments will be triggered when a value is being overridden by said experiment.
This greatly simplifies the process of setting up experiments and cleaning up your code. If, at some point, a large part of the code is set up in this way you will be able to create different experiments without touching a single line of code.
Translations Example
This is an advanced pattern. If you don't need multi-language support, the basic example above is all you need.
Let's look at a more complex example where you run an experiment whilst accommodating multiple languages.
Here, we have a languagesConfig.js file:
export default // Copy text for English and Dutch
{
header: {
en: "Our nice header!",
nl: "Onze leuk kop!",
},
call_to_action1: {
en: "Click here",
nl: "Klik hier",
},
};
In our code, we can then get all of our variant variables using:
// Get the keys of the variant variables from the context
const tagsToFetch = context.variableKeys();
const translationVariations = fetchTranslations(tagsToFetch);
The translationVariations variable would then be returned as something like:
{
"header_v1": {
"en": "Our beautiful header!",
"nl": "Onze mooie kop!"
},
"call_to_action1_v1": {
"en": "Continue",
"nl": "Doorgaan"
}
}
...which you could then merge with your original translations, like so:
import appTranslations from "../languagesConfig.js";
const translations = mergeConfig(appTranslations, translationVariations);
...which would return an object with getter properties (shown here as pseudocode):
{
header: -> calls treatment("experiment1"), returns { en: "Our beautiful header!", nl: "Onze mooie kop!" }
call_to_action1: -> calls treatment("experiment2"), returns { en: "Click here!", nl: "Klik Hier" }
}
You can now use this object to run your experiments whilst still supporting multiple languages!
Next steps
You've reached the end of the SDK Guide. For per-SDK API details beyond what's covered here, check the README in each SDK's GitHub repository (linked on the SDK Guide overview). If you have questions, reach out to our team through the Web Console.