Core Concepts

String Variants

A/B test string values by attaching an experiment to a key: deterministic, stateless, cross-platform selection driven by an assignment id, with exposure events you forward to your own analytics.

Variants let you A/B test the value of a string. You attach an experiment to one string key; the experiment carries traffic-allocation weights and a text value per variant. When a variant is selected, it overrides the base value for that key. Everywhere else the base value is served unchanged.

The user-facing feature is called variants; the API object is an experiment. One experiment attaches to exactly one key. You create and run experiments from the terminal — see CLI variants.

How selection works

Selection is driven by a stable assignment id you set on the SDK:

setAssignmentId(id)

The id is typically a user id or device id — anything stable per person. Setting it recomputes selection immediately from the already-verified current bundle: no server round-trip, no local state to persist. Passing null clears the assignment and serves base values.

Selection is deterministic and stateless, and byte-identical across every platform. The same assignment id resolves to the same variant on iOS, Web, Android, and React Native. Bucketing:

bucket = BE_uint32(SHA-256(UTF8(experimentId + ":" + assignmentId))[0..3]) mod 100

This yields a bucket in 0..99. Allocation names are sorted lexicographically by Unicode code point; weights are accumulated; the first name where bucket < acc is selected.

Locale is deliberately not part of the hash input. The same assignment resolves to the same variant across every locale, so a user's experience is consistent no matter which language they see.

Per-SDK method names and code live on the SDK pages: iOS, Web, Android, React Native.

Exposure and analytics

The SDK fires one exposure event per resolved experiment read. Exposures are deduped per SDK-instance session on key + experimentId + variant + assignmentId. Locale is excluded from the dedupe key, so a user counts once per experiment regardless of how many locales they read. Delivery is asynchronous — the exposure is queued after the string read returns, never inline.

Each event carries exactly these fields:

FieldMeaning
keyThe string key the experiment is attached to
experimentIdThe experiment that resolved
variantThe selected variant name (e.g. control)
localeThe locale the string was read in
assignmentIdThe assignment id in effect at read time

You forward these to your own analytics pipeline. The SDK ships no telemetry of its own — it never phones home.

Signing and soft-fail

Experiment definitions are covered by a separate experiments_signature, Ed25519-verified independently and after the main bundle signature. This keeps variants on the same no-unsigned-content guarantee as the rest of delivery — see Bundles, signing, and the CDN.

Variants never block strings and never serve an unverified value. On any failure the SDK soft-fails to base values and still accepts and serves the bundle:

  • No assignment id set
  • Invalid allocation
  • Missing value for the selected variant
  • A bad or absent experiments_signature
  • An old, pre-variants bundle

An SDK version without variants support reads a variants bundle as if the experiments block weren't there and simply serves base values.

Limits

Enforced server-side when you define an experiment:

  • At most 10 variants per experiment.
  • Variant names match ^[a-z0-9_]{1,64}$. control is a reserved name.
  • Variant values are at most 10000 characters.
  • MVP is text format onlyicu keys are rejected server-side.

Availability

Variants shipped in iOS 1.1.0, Web 1.1.0, Android 1.1.0, and React Native 0.2.0. It is an additive, backward-compatible minor release: existing integrations compile and run unchanged, and an old SDK reading a variants bundle simply serves base values.

On this page