Skip to content
Private betaTreebars is letting teams in from the waitlist.Join the waitlist

Remote config

A value your app reads by name and you change from the dashboard, without a release: a feature flag, a price, a headline. One call to read it, and nothing to set up beyond the SDK you already have.

Remote config needs SDK 0.6.0 or later, on every platform.

Make a variable

In the dashboard, open Remote config and add a variable. Give it a key your code will use — new_checkout — choose what kind of value it is (on/off, text, a number or JSON) and its default. Add rules if some people should get something else: a platform, an app version, a share of everybody. Nothing reaches an app until you press Publish.

Read it

getConfig takes the key and a fallback, and answers a value of the same kind as the fallback.

Webts
import treebars from '@treebars/web-sdk';

if (treebars.getConfig('new_checkout', false)) showNewCheckout();

const headline = treebars.getConfig('home_headline', 'Welcome');
const limit = treebars.getConfig('upload_limit_mb', 25);
const layout = treebars.getConfig('home_layout', { columns: 2 });
iOSswift
if Treebars.getConfig("new_checkout", fallback: false) { showNewCheckout() }

let headline = Treebars.getConfig("home_headline", fallback: "Welcome")
let limit = Treebars.getConfig("upload_limit_mb", fallback: 25)
Androidkotlin
if (Treebars.getConfig("new_checkout", false)) showNewCheckout()

val headline = Treebars.getConfig("home_headline", "Welcome")
val limit = Treebars.getConfig("upload_limit_mb", 25)
React Nativets
import treebars from '@treebars/react-native-sdk';

await treebars.init({ write_key: 'pk_live_…' });   // read after init has resolved

if (treebars.getConfig('new_checkout', false)) showNewCheckout();
const headline = treebars.getConfig('home_headline', 'Welcome');

A read never waits and never fails. It answers from what the device already holds, so it is safe while a screen is being drawn, on the main thread, offline.

The fallback

The fallback is what the read answers until the device holds a value for the key — a first launch, no connection yet, somebody who opted out. Pass the value your app behaves with today, and adding the read changes nothing by itself.

It also says which kind of value you expect. The kind is read from the fallback and never from what was published: if somebody sets a flag to the text "false" by mistake, your getConfig('new_checkout', false) still answers false, not a piece of text that reads as on. An empty fallback is fine — '', 0 and false are each still a kind.

When you have no fallback

Sometimes there is no sensible default — a banner that should only appear once its text exists. Name the kind instead, and the read answers nothing until a value is held.

Web and React Nativets
const banner = treebars.getConfigString('promo_banner');   // string, or null
if (banner) showBanner(banner);
iOSswift
if let banner = Treebars.getConfigString("promo_banner") { showBanner(banner) }
Androidkotlin
Treebars.getConfigString("promo_banner")?.let { showBanner(it) }
Kind
On / off
Read
getConfigBoolean(key)
Answers
true, false, or nothing
Kind
Text
Read
getConfigString(key)
Answers
the text, or nothing
Kind
Number
Read
getConfigNumber(key)
Answers
the number, or nothing
Kind
JSON
Read
getConfigJson(key)
Answers
the value, or nothing

Each also takes a fallback, and is then exactly what getConfig calls. On iOS and Android a JSON value is read this way — getConfigJson answers JSON text for you to decode with your own types — and a number read with a whole-number fallback answers a whole number.

When values arrive

There is no fetch to call. The SDK asks for the values by itself when a newer config has been published and when who is asking changes, and keeps them on the device — so a launch starts on the values the last one held.

A first launch has none yet, and starts on your fallbacks; its values arrive a moment after the app opens. To start a first screen on the published values instead, wait for them. It gives up after two seconds and carries on with your fallbacks.

Web and React Nativets
await treebars.configReady();        // or configReady(500) for half a second at most
render();
iOSswift
await Treebars.configReady()
render()
Androidkotlin
Treebars.configReady()   // a suspend function
render()

A key keeps its answer for the session

The first read of a key fixes its answer until the session ends. A newer config published while somebody is half-way through a checkout does not change that checkout under them; it applies from their next session. A key that has not been read yet takes the newest values straight away.

To apply new values sooner, call activateConfig() at a moment you can redraw — it answers whether any read would now answer differently. onConfigChange tells you when that may be so, and returns the function that stops it.

ts
const stop = treebars.onConfigChange(() => {
  if (treebars.activateConfig()) redrawHome();
});

What a rule can read

A rule in the dashboard can already read the platform, the app version, the language, the country and whether somebody is signed in — nothing to send. For anything else your app knows, say it once. It is the whole set each time: a key you leave out is no longer set.

Webts
treebars.setConfigAttributes({ plan: 'pro', seats: 5 });
iOSswift
Treebars.setConfigAttributes(["plan": "pro", "seats": 5])
Androidkotlin
Treebars.setConfigAttributes(mapOf("plan" to "pro", "seats" to 5))
React Nativets
await treebars.setConfigAttributes({ plan: 'pro', seats: 5 });

Signing in or out asks for the values again, since the answer may differ. A sign-out forgets the account's values at once, before the next ones arrive, so the next person on the device is never shown the last one's.

Experiments

A variable can serve an experiment: two to five values, each to a share of people. Your code does not change — it is the same read. When a read answers an experiment's value, the SDK records experiment_exposed with the variant, at most once a day for each person, so who saw which variant is counted from what your app actually showed and not from what it was sent.

That is what lets the dashboard compare the variants afterwards: Insights has an Experiment view that reads the whole page once for each variant, and a user flow can be divided at a step by the variable.

Read the value where it is used. A read made at launch for a screen somebody never opens counts them as having seen a variant they did not.

While you build

An override answers a key on this device whatever was published — for trying a variant without changing the dashboard. It is never stored and never sent: the next launch or reload forgets it, and it records no exposure.

Webts
treebars.setConfigOverride('new_checkout', true);
treebars.setConfigOverride('new_checkout', undefined);   // take it back
iOSswift
Treebars.setConfigOverride("new_checkout", value: true)
Androidkotlin
Treebars.setConfigOverride("new_checkout", true)
React Nativets
await treebars.setConfigOverride('new_checkout', true);

allConfig() lists every value the device holds, for a debug screen. fetchConfig() asks for the values now and answers whether they arrived; it is seldom needed, since the SDK asks by itself.

Somebody who opted out

After optOut() the SDK asks for nothing about that person, and every read answers its fallback. Your app keeps working on the values it ships with.