A/B testing paywalls
stubkit lets you run paywall experiments — pick two (or more) offerings, split traffic, and watch conversion rate per variant. Users are bucketed consistently: the same user always sees the same variant.
How it works
- You create an experiment in the dashboard under
/apps/{id}/experimentswith a slug and 2+ variants. Each variant points to an existing offering. - On the device, the SDK calls
GET /v1/experiments/{app_id}/{slug}?user_id={uuid}. The server hashesuser_id + experiment_idwith SHA-256 and picks a variant weighted by the experiment's weights. - The SDK renders the returned offering and reports events (view, purchase, dismiss) to
POST /v1/paywall-events. - The dashboard shows conversion rate, unique viewers, and revenue per variant, with a "leading" badge on the top performer (only when signal is sufficient).
Bucketing guarantees
Because bucketing is a deterministic hash of the user id, results are stable across devices, app restarts, and cache clears. Adding a new variant reshuffles users — plan experiments accordingly.
Example — pricing test
POST /v1/admin/experiments
{
"app_id": "notesam",
"slug": "pricing-q2-2026",
"description": "Does a 7-day trial convert better than no trial?",
"variants": [
{ "variant_key": "control", "offering_slug": "default", "weight": 50 },
{ "variant_key": "trial", "offering_slug": "with-trial", "weight": 50 }
]
}Reading results
The results endpoint returns per-variant views, purchases, unique viewers, revenue, and conversion rate (as a percentage). For statistical significance, aim for at least 500–1000 views per variant before declaring a winner — the dashboard shows an "early" hint below that threshold.
GET /v1/admin/experiments/{id}/results
{
"experiment": { "id": "...", "slug": "pricing-q2-2026", "active": 1 },
"variants": [
{
"id": "...",
"variant_key": "control",
"views": 842, "purchases": 34,
"unique_viewers": 820,
"conversion_rate": 4.04,
"revenue_cents": 33966
},
{
"id": "...",
"variant_key": "trial",
"views": 861, "purchases": 51,
"unique_viewers": 839,
"conversion_rate": 5.92,
"revenue_cents": 50949
}
]
}Ending an experiment
When you're confident in a winner, set the losing variant's offering to inactive (so new users flow into the winner) and pause the experiment. Existing subscribers aren't affected either way.