The experiments module assigns users to variants using a deterministic hash. No server call is needed — assignment is instant, works offline, and the same user always gets the same variant.
Get Variant
val variant = AppDNA.experiments.getVariant("paywall-test")
when (variant) {
"control" -> showStandardPaywall()
"variant_a" -> showNewPaywall()
else -> showStandardPaywall() // Always handle the default case
}
Returns the variant string or null if the experiment is not found, not running, or the user is not in the target audience.
Always handle the null / else case. Experiments can be archived or stopped at any time from the Console.
Module Access
val experiments = AppDNA.experiments
Module Methods
| Method | Signature | Description |
|---|
getVariant | getVariant(experimentId: String, trackExposure: Boolean = true): String? | Get the assigned variant |
trackExposure | trackExposure(experimentId: String) | Manually track an exposure event |
setDelegate | setDelegate(delegate: ExperimentDelegate?) | Set a delegate for assignment callbacks |
Exposure Tracking
Automatic (Default)
The SDK tracks an experiment_exposure event once per session the first time getVariant() is called for a given experiment.
Manual
Disable automatic tracking and track when the UI is actually visible:
val variant = AppDNA.experiments.getVariant("paywall-test", trackExposure = false)
// Later, when the paywall is actually displayed
fun onPaywallVisible() {
AppDNA.experiments.trackExposure("paywall-test")
}
ExperimentDelegate
Register a delegate to be notified when experiment assignments change:
AppDNA.experiments.delegate = object : ExperimentDelegate {
override fun onAssignmentChanged(experimentId: String, newVariant: String?) {
println("Experiment $experimentId now: ${newVariant ?: "none"}")
}
}
Assignment changes are rare. They occur only when the experiment definition changes on the server, not on every session start.
Experiment Lifecycle
| Status | getVariant() returns |
|---|
| Draft | null — not visible to SDKs |
| Running | Assigned variant string |
| Completed | Winning variant for all users |
| Archived | null — removed from config |
Full Example
import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.ExperimentDelegate
import ai.appdna.sdk.PaywallContext
class PaywallExperiment(private val activity: Activity) : ExperimentDelegate {
init {
AppDNA.experiments.delegate = this
}
fun showPaywall() {
val variant = AppDNA.experiments.getVariant("paywall_redesign")
val paywallId = when (variant) {
"new_design" -> "paywall_v2"
else -> "paywall_v1"
}
AppDNA.paywall.present(
paywallId, activity,
context = PaywallContext(
placement = "settings",
experiment = "paywall_redesign",
variant = variant ?: "control"
)
)
}
override fun onAssignmentChanged(experimentId: String, newVariant: String?) {
// Assignment changed mid-session (rare)
}
}
Experiments are created in the Console under Experiments. The SDK uses MurmurHash3 for deterministic assignment — the same user always gets the same variant across sessions, platforms, and even offline.