Every subscription app reaches the same point: you have a paywall, it converts at some rate, and you want to know if a different version would convert better. The obvious answer is A/B testing. The less obvious part is doing it without shipping an app update every time you want to try a new headline.
Most teams either hardcode their paywall UI and test through app releases (slow, expensive, limited iterations) or use a paywall platform that offers built-in experimentation through a dashboard (faster, but opaque and hard to integrate with existing analytics). There's a third approach: define paywalls as remote JSON schemas, run experiments server-side, and let the native SDK render whatever variant the server assigns.
Why remote paywall testing matters
App Store review takes anywhere from a few hours to a few days. If your paywall is compiled into the app binary, every test iteration requires a new build, a new submission, and a new waiting period. Even with TestFlight, you're limited in how fast you can iterate.
Remote paywalls decouple the paywall definition from the app release cycle. The app ships with a rendering engine that knows how to display a paywall from a JSON schema. The schema lives on a server. When you want to test a new variant, you create a new schema and configure the experiment — no app update needed.
This means you can run multiple experiments per week instead of one per release cycle. You can test small changes (a single word in the headline) and big changes (completely different layouts) with the same mechanism.
Setting up an experiment
A paywall experiment needs three things: two or more paywall variants, a traffic allocation rule, and a way to track which variant each user saw and whether they converted.
Start by defining your variants as separate paywall schemas. Here's a control variant:
{
"id": "pricing_control",
"name": "Standard Pricing",
"type": "modal",
"products": ["monthly_9.99", "annual_79.99"],
"header": {
"title": "Go Premium",
"subtitle": "Unlock all features"
},
"features": [
{ "icon": "check", "text": "Unlimited projects" },
{ "icon": "check", "text": "Advanced analytics" },
{ "icon": "check", "text": "Priority support" }
]
}
And here's a treatment variant that tests different pricing and copy:
{
"id": "pricing_treatment",
"name": "Value Pricing",
"type": "modal",
"products": ["monthly_6.99", "annual_49.99"],
"header": {
"title": "You're missing out",
"subtitle": "Join 50,000+ users who upgraded"
},
"features": [
{ "icon": "star", "text": "Everything in Free, plus:" },
{ "icon": "zap", "text": "10x faster exports" },
{ "icon": "shield", "text": "Offline access" }
]
}
Then create the experiment resource that ties them together:
{
"name": "Q1 Pricing Experiment",
"placement": "main_paywall",
"variants": [
{ "paywall": "pricing_control", "weight": 50 },
{ "paywall": "pricing_treatment", "weight": 50 }
],
"goals": ["trial_start", "paid_conversion"],
"status": "running"
}
When a user hits the paywall placement, the server assigns them to a variant based on the weight distribution. The assignment is sticky — the same user always sees the same variant for the duration of the experiment.
What to test
Not all paywall changes are worth testing. Focus on variables with high expected impact:
- Pricing and plan structure. This is usually the highest-leverage change. Test different price points, trial lengths, and whether to show monthly vs. annual options.
- Headline and subtitle copy. The first thing users read. Test benefit-driven vs. urgency-driven vs. social proof headlines.
- Feature list. Which features you highlight and how you describe them can shift conversion. Test different orderings and descriptions.
- Layout type. Modal vs. full-screen vs. bottom sheet. The presentation format affects how users engage with the paywall.
- Number of products. Show one plan, two plans, or three plans with a recommended badge. More options isn't always better.
- CTA button text. "Start Free Trial" vs. "Try It Free" vs. "Continue" — small copy changes can move conversion rates.
Avoid testing too many variables at once. If you change the headline, the pricing, and the layout simultaneously, you won't know which change drove the result. Run one-variable tests when possible, and use multivariate testing only when you have enough traffic to reach significance across all combinations.
Mistakes teams make
The most common mistake is ending experiments too early. Subscription conversion has natural variance — weekday vs. weekend traffic, seasonal effects, marketing campaign overlap. An experiment that looks like a clear winner after 48 hours might regress to neutral after two weeks. Set a minimum sample size before you start and stick to it.
The second mistake is not tracking the right metric. Trial starts are easy to measure but they're a vanity metric if those trials don't convert to paid subscriptions. Track the full funnel: paywall view, trial start, trial-to-paid conversion, and ideally retention at 30 and 90 days. A variant that gets more trial starts but worse trial-to-paid conversion might net fewer paying users.
The third mistake is testing without a hypothesis. "Let's see if a blue button works better" is not a hypothesis. "Users are bouncing because the price feels high relative to perceived value, so emphasizing the annual discount should improve conversion" is a hypothesis. You need a reason to believe the change will work, otherwise you're just generating noise.
Finally, watch out for interaction effects with other experiments. If you're running a pricing test on the paywall while your growth team is running a different onboarding flow experiment, the two can interact in unpredictable ways. Either coordinate your experiments or use a system that accounts for interaction effects.
Technical requirements
To run remote paywall experiments effectively, your stack needs a few things:
- A schema-driven rendering engine. The client SDK must be able to render any paywall from a JSON schema without hardcoded layouts. This is the foundation — without it, every variant requires a code change.
- Sticky assignment. Users must see the same variant every time they encounter the paywall during an experiment. This typically means hashing the user ID with the experiment ID and using the hash to determine assignment.
- Event tracking with variant attribution. Every paywall event (view, dismiss, tap, purchase) must include the experiment ID and variant ID. Without this, you can't attribute conversions to variants.
- Statistical significance calculation. Don't eyeball the results. Use a proper statistical test — at minimum a chi-squared test for conversion rate differences. Bayesian methods work well for subscription metrics because they handle low-volume events better.
- Experiment lifecycle management. You need the ability to start, pause, and stop experiments, and to promote a winning variant to 100% traffic. Ideally this is an API operation, not a manual process.
If your paywall platform provides all of this through an API, you can wire it into your existing analytics and experimentation infrastructure. If it only provides a dashboard, you're stuck with whatever analytics the vendor gives you — which is usually not enough for serious analysis.
Putting it together
The best paywall testing setup is one where creating an experiment is as easy as creating a pull request. Define variant schemas in your repo, push to a branch, and let your CI pipeline create the experiment through the API. When the experiment concludes, merge the winning variant and archive the loser.
This keeps your paywall experimentation in the same workflow as everything else your team ships. No context-switching to a dashboard, no manual data export, no "who changed the paywall last week?" questions in Slack. Just code, data, and version control.
Try AgentWallie
API-first paywall platform. Paywalls as JSON schemas. MCP as a first-class interface.
Read the Docs