sdk-sourced variables. The same attributes also drive audience targeting at resolve time, so the data you send does triple duty: content, in-flow conditions, and who sees the flow at all.
The VariableValue type
Every variable value the SDK hands you is aVariableValue, a public enum with typed accessors. Use the accessor for the type you expect; it returns nil if the value is absent or the wrong type.
| Accessor | Returns | Notes |
|---|---|---|
.stringValue | String? | |
.numberValue | Double? | Coerces a numeric string (for example "9.99"). |
.intValue | Int? | Coerces a numeric string; truncates a Double. |
.boolValue | Bool? | Coerces "true"/"1"/"yes" and non-zero numbers. |
.stringListValue | [String]? | |
.numberListValue | [Double]? | |
.booleanListValue | [Bool]? |
isEmpty, the type-check flags isString / isNumber / isBoolean / isList, typeName, and displayString (the same string the SDK uses when interpolating {{var}} into text).
Setting context at launch
Pass acontext dictionary when you configure the SDK. SDKContext is a public typealias for [String: Any].
sdk. On the dashboard a flow variable defined as an App Parameter carries a source like:
path as a literal, flat key in your context dictionary. So a variable with path: "user.isPremium" reads context["user.isPremium"]. The dot is part of the key, not a nested-object lookup. Send flat keys with dots in them, not nested dictionaries.
defaultValue (or the type default: "", 0, false, or an empty list).
Updating context later
updateContext merges new values into the SDK’s context dictionary:
additionalContext instead. It is merged on top of the launch context for that one session:
additionalContext seeds the variables for that presentation only. It does not affect audience targeting, because the placement is resolved before the session is created. Targeting always uses the launch context plus any values added with updateContext. See the targeting section below.Reading and writing variables during a flow
A live flow exposes its variables through theFlowSession you hold (from createSession or FlowPresenterView). All four methods are public.
VariableValue conforms to the standard literal protocols, so you can write session.setVariable("count", value: 3) or .setVariable("active", value: true) directly.
After a flow ends, read the final state from FlowResult.finalVariables, keyed by variable key.
The targeting connection
When the SDK resolves a placement, it sends your context (plus a few device and app attributes) as the attributes the dashboard audience filters match against. The SDK adds these automatically:device.platform(always"ios")device.os_version,device.modelapp.version(CFBundleShortVersionString),app.build(CFBundleVersion)
user.isPremium == true matches the context key user.isPremium you provided at launch. The filter property name on the dashboard must match the context key you send, exactly.
Audience filters and flow-variable resolution can treat dotted property names differently (variable resolution uses a flat-key lookup; the resolver may treat a filter property as a nested path). When you target on a dotted property, confirm it matches as expected. See Audience targeting for how filters evaluate properties.
Example: one attribute, three uses
Configure the SDK once:- Content: a
textcomponent bound to{{user.id}}(a flow variable withsource { kind: "sdk", path: "user.id" }) renders the id in the flow. - In-flow logic: a Dynamic Value branches on the
user.isPremiumvariable to show a different headline. See Dynamic values. - Audience: a placement audience filter
user.isPremium == falseso only non-premium users get the paywall flow.
A stable user id is automatic
Experiment bucketing is sticky on the user id. The SDK generates one persistent id per install and stores it in the Keychain, so a given device keeps the same variant across launches without any work from you.Common mistakes
- Context key does not match the variable’s
sdkpath. The key you send must equal the variable’spathcharacter for character, dots included. A mismatch leaves the variable on its default. - Nesting context and expecting dot-paths to resolve. Variable resolution is a flat-key lookup. Send
["user.id": ...], not["user": ["id": ...]]. - Calling
updateContextto change a flow already on screen. It only affects the next resolve and the next session. Update before presenting. - Writing to a read-only variable and assuming it took. App Parameters (
sdk-sourced variables) are created read-only in the editor.setVariablereturnsfalseand the write is ignored. Check the return value. - Sending non-JSON types. Context values are
Any, but stick toString, numbers,Bool, and arrays of those so they convert cleanly.