Experiments
Run A/B tests to optimize pricing, paywalls, onboarding flows, and feature adoption. AppActor handles user assignment, targeting, and variant delivery.
How It Worksโ
- Create an experiment on the server with variants and targeting rules
- Request assignment from the SDK โ the server assigns the user to a variant
- Use the variant to show different UI or behavior
- Track goals to measure which variant performs better
Getting a Variantโ
- iOS
- Android
- Flutter
- React Native
if let assignment = try await AppActor.shared.getExperimentAssignment(
experimentKey: "paywall_v2"
) {
// Assignment exists โ user is in experiment
switch assignment.variantKey {
case "control":
showOriginalPaywall()
case "variant_a":
showNewPaywall()
default:
showOriginalPaywall()
}
// Optional payload access
if let showDiscount = assignment.payload["showDiscount"]?.boolValue, showDiscount {
showDiscountBadge()
}
} else {
// User not targeted or experiment not running
showOriginalPaywall()
}
Coming Soon
Android SDK is currently in development.
Coming Soon
Flutter SDK is currently in development.
Coming Soon
React Native SDK is currently in development.
Experiment Structureโ
Key Conceptsโ
| Concept | Description |
|---|---|
| Experiment Key | Unique identifier (e.g., "paywall_v2") |
| Traffic Allocation | Percentage of eligible users included (in basis points, 10000 = 100%) |
| Targeting | Rules to filter eligible users (same as Remote Config) |
| Variant | A named group with a weight and payload |
| Control | The baseline variant (usually current behavior) |
| Weight | Percentage of experiment traffic for this variant (in basis points) |
| Payload | Arbitrary JSON data attached to the variant |
| Sticky Assignment | Once assigned, a user always sees the same variant |
REST APIโ
Request Assignmentโ
POST /v1/experiments/paywall_v2/assignments?app_user_id=user_123
Authorization: Bearer pk_live_your_key_here
Query Parameters:
| Parameter | Required | Description |
|---|---|---|
app_user_id | Yes | User ID (max 256 characters) |
app_version | No | App version for targeting |
country | No | ISO 3166-1 alpha-2 code for targeting |
Response (Assigned)โ
{
"data": {
"experiment": {
"id": "exp_abc123",
"key": "paywall_v2"
},
"variant": {
"id": "var_xyz789",
"key": "variant_a",
"valueType": "json",
"payload": {
"layout": "new",
"showDiscount": true
}
},
"inExperiment": true,
"assignedAt": "2025-01-15T12:00:00.000Z"
},
"requestId": "req_abc123"
}
Response (Not Targeted)โ
{
"data": {
"inExperiment": false,
"reason": "not_targeted"
},
"requestId": "req_abc123"
}
Targeting Conditionsโ
Same targeting system as Remote Config:
| Condition | Operators | Example |
|---|---|---|
| Platform | eq, neq, in, not_in | iOS only |
| App Version | eq, gt, gte, lt, lte | v2.0.0+ |
| Country | eq, neq, in, not_in | US and CA |
| Entitlement | has, not_has | Free users only |
Goalsโ
Track what you're optimizing for:
| Goal Type | Description |
|---|---|
conversion | Did the user convert (e.g., subscribe)? |
revenue | Revenue generated |
retention | User retention after N days |
custom | Custom event tracking |
Best Practicesโ
- Always handle the "not in experiment" case โ Show default behavior when the user isn't targeted
- Use the control variant โ Always have a control group for comparison
- Check assignment early โ Fetch the assignment before rendering the UI
- Don't change experiments mid-flight โ Let experiments run to completion for valid results
Next Stepsโ
- Apple Search Ads โ Attribution tracking