Default Values & Fallback
The ABetterChoice SDK is designed to never block your application's hot path. When the platform cannot be reached, the SDK falls back to one of three sources, in this order:
- the local cache from the most recent successful poll;
- the precomputed bundle stored on disk by client SDKs across app launches;
- the default value you pass when reading the parameter or feature flag.
This page describes how each layer behaves so you can choose safe defaults and reason about what your code does when the platform is degraded.
The Go and HTTP code paths below are generally available today. The Android, iOS, JavaScript, and C++ snippets are a shape preview — those SDKs are tagged
Coming soonunderSettings → SDK&Key.
Read API shape
Every SDK exposes typed read APIs that take a default. The default is what the call returns when the parameter or feature flag is missing, the network is down, or the experiment is archived.
// Go
show := exp.GetBoolWithDefault("should_show_banner", false)
size := exp.GetInt64WithDefault("size", 16)// C++
auto exp = AbcService::GetInstance()->GetExperiment("6666", "abc_layer_name", WithSetUnitID(uid));
std::string color = exp.GetString("color"); // empty string when missing// Android
AbcExpInfo info = mAbcExperiment.getExperiment("abc_layer_name");
boolean show = info.getBooleanValue("should_show_banner", true);
String copy = info.getStringValue("copy", "Default copy");// JavaScript
const exp = abc.getExperiment("abc_layer_name", true);
const show = exp.getBoolValue("should_show_banner", true);The default value is a first-class part of the contract: pick a value that keeps the system correct even if the user is never assigned to any experiment.
Fallback flow
In practice you will only see the default value during:
- the very first call before init resolves (avoid by awaiting
initbefore reading); - a network outage that lasts longer than the SDK's grace period;
- a project that has never returned a value for that parameter / feature flag (typo, archived, or removed).
Server SDK behaviour
Server SDKs poll every 3 seconds and keep configurations in memory. If the polling endpoint is unreachable for one cycle, the SDK keeps serving the last good cache. There is no on-disk persistence — when the process restarts, init must succeed before reads return real values.
Practical advice:
- have your init step block with a bounded timeout (default 15 seconds) so the service does not start serving traffic with empty caches;
- log a metric for "init succeeded" vs "fell back to defaults" so you notice silent regressions;
- never pick a default that is more invasive than the control group — the default is what users see when the platform is silent.
Client SDK behaviour
Client SDKs persist the last successful bundle to local storage (MMKV on Android / iOS, localStorage on web). On the next launch:
- the SDK returns the persisted value immediately so the UI does not flash defaults;
- a background fetch refreshes the cache;
- if the fetch fails, reads keep returning the persisted value and only fall back to the parameter default when the local file is missing or corrupted.
Practical advice:
- gate UI changes on the parameter, not on a network signal — the SDK already handles the retry;
- design defaults that match the control experience, so a first-launch user sees the same UI as a returning user before the cache hydrates;
- set
enableAutomaticPoll: trueon long-running web sessions so updates pushed during the session take effect within the standard 10-minute window.
HTTP API behaviour
The HTTP API has no client-side cache. Every call is a new network request:
- on transport failure, the call returns an error; your client picks the default;
- on
ret_code == 100with a layer absent fromexp_data, the unit was not assigned to any experiment in that layer — pick the default; - on
ret_code != 100, treat the call as failed and pick the default. See HTTP API endpoints for the full table.
Choosing a safe default
Apply these three rules and you will not regret a default:
- Default to the control branch, never the treatment. If the treatment can break the user flow, the default must keep the flow working.
- Use static defaults, not "the most common assignment". A static default is reproducible and testable; a dynamic one moves under your feet during incidents.
- Match the type exactly. A
Booleanparameter with a string default is a future bug — the typed APIs above prevent this if you use them consistently.