Flags and typed values
Read boolean, string, number and JSON object flag values in a hybrid app, validate typed objects, and control when Apex records an exposure.
Read a flag at the point where the app selects its content or code path. Every read returns a value: the assigned value, a cached value, or your default.
Read a primitive flag
import { Apex } from '@drip-apex/app-sdk';
const showBanner = Apex.flag('checkout_banner', false);
const ctaLabel = Apex.flag('cta_label', 'Buy now');
const freeShippingFrom = Apex.flag('free_shipping_from', 50);The default sets the type. The assigned value must have the same JSON type: boolean, string or number. The SDK does not convert types. For example, the string "true" does not match a boolean default. Numbers must be finite, and integers must be safe JavaScript integers.
A missing or incompatible value returns the default. The SDK logs a warning once per key per session, but only after it has loaded an assignment set from cache or the network. Reads before that first load return defaults without warnings.
Read a typed object
Create the flag with object values in Apex. Then read it with flagObject and a validator:
type Welcome = { title: string; button: { label: string; enabled: boolean } };
const fallback: Welcome = { title: 'Welcome', button: { label: 'Start', enabled: false } };
const isWelcome = (v: unknown): v is Welcome => {
if (!v || typeof v !== 'object') return false;
const x = v as Partial<Welcome>;
return typeof x.title === 'string'
&& typeof x.button?.label === 'string'
&& typeof x.button?.enabled === 'boolean';
};
const content = Apex.flagObject('welcome', fallback, { validate: isWelcome });TypeScript types do not check nested fields at runtime. Without a validator, flagObject checks only the outer JSON type. Use a validator for every object flag.
- A value that passes validation is returned as a copy. Unknown keys stay in the copy.
- A value that fails validation, or a validator that throws, returns the default. The SDK logs a warning and records no exposure.
- The SDK never throws into app code.
Change values without an app release
Each variation value must be JSON with finite numbers, at most 16 KB after serialization. You can edit a value later in Apex or with PATCH /api/v1/flags/{id}. The app gets the new value on its next successful assignment refresh, without an app release.
Typed values replace code variants for content and configuration tests. Layout and flow tests still need both versions in your app code behind the flag. Apex cannot remove that code from the app for you.
Exposures
An exposure tells Apex that a user saw a variation.
By default, a read records the exposure automatically. This applies to flag, flagObject and variation. The SDK records one exposure per test and variation per session, so repeated reads are safe.
- A read of a missing assignment records no exposure.
- A read of an incompatible or invalid value records no exposure.
- A read while
identify()is pending records no exposure. See Users and identity.
Manual exposure
Read the value early and record the exposure only when the user can see the result. Use exposure: 'manual' and call logExposure later:
const content = Apex.flagObject('welcome', fallback, { validate: isWelcome, exposure: 'manual' });
// Later, when the welcome content is on screen:
Apex.logExposure('welcome');flag accepts the same option: Apex.flag('checkout_banner', false, { exposure: 'manual' }).
Manual exposures use the same per-session dedupe, so a repeated logExposure call is safe. A logExposure call while identify() is pending is ignored and is not replayed later. Call it again after the new assignments load.
Read the variation
variation(key) returns details about the assigned variation. It also records the exposure.
const v = Apex.variation('welcome');
// { id, index, isControl, kind, value, reason }reason | Meaning |
|---|---|
fresh | The value came from the network less than 60 seconds ago. |
cached | The value came from the device cache. |
stale | The value is more than 60 seconds old. |
default | The user has no assignment for this flag. |
For a flag the user is not assigned to, variation returns an object with an empty id, value: null and reason: 'default'; it records no exposure then. It returns null only before configure(), for an invalid key, and when the stored value is not valid JSON. Use flag() or flagObject() with exposure: 'manual' when you need a value without counting an exposure.
React to changes
Values can change after a refresh. Subscribe to update the UI:
const subscription = Apex.onChange((change) => {
if (change.type === 'changed' && change.keys.includes('welcome')) {
// Read the flag again and update the UI.
}
if (change.type === 'stopped') {
// The SDK stopped networking, for example after an invalid key.
}
});
// When the view closes:
subscription.cancel();End a test
When you conclude a flag in Apex, every user gets the winning variation. Apps receive the winner on their next successful assignment request: at startup, when the app returns to the foreground, or after Apex.refresh(). A session that stays in the foreground keeps its earlier value until that request succeeds. Users in a global holdout get no assignment and keep your default value.
Then remove the flag read from the app and release a new version. Archive the flag when Apex reports that the app no longer calls it. The Removal checklist on the flag page shows this status.