A paywall renders an offering; an offering groups products; products grant entitlements. Change the paywall all you want. Your client code keeps checking the same entitlement.
Paywalls
Design server-driven paywalls, publish them over the air, and optimize revenue with A/B experiments.
A paywall is the screen that sells an offering: the set of products a customer can buy. In CashSDK, paywalls are configured on the server and fetched by the SDK at runtime, so you can restyle pricing, copy, and layout without shipping an app update.
Create a paywall#
Start from the visual editor in the dashboard, or from a prebuilt template. List available templates:
curl https://api.cashsdk.com/v1/templates \
-H "Authorization: Bearer csk_sk_..."
Create it against your app via the API. The offering, its products, and display metadata are all part of the payload.
curl https://api.cashsdk.com/v1/apps/{app}/paywalls \
-H "Authorization: Bearer csk_sk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Main Paywall",
"identifier": "main",
"offering": "default",
"products": ["pro_monthly", "pro_annual"],
"template": "hard-sell",
"targeting": { "platform": ["ios", "android"] }
}'
Point your coding agent at the CashSDK MCP server and
call the generate_paywall tool. Describe the offer in plain language and it
scaffolds the paywall, wires the products, and publishes a draft for review.
Present with the SDK#
Register a placement and CashSDK resolves the campaign, audience and experiment for you, then presents the paywall your team configured in the dashboard. It is fire-and-forget: with no campaign, no network, or a bad config it silently advances, so your app is never blocked by a paywall it could not load.
CashSDK.shared.register(placement: "onboarding_finished")
CashSDK.shared.register(placement = "onboarding_finished")
Building the UI yourself instead? Read prices from the native store
(Product.products(for:) on iOS) and pass the selected product identifier to
purchase(_:).
Register placements early (for example on app launch). The SDK keeps the paywall in sync in the background, so the next fetch reflects any change you publish.
Update over the air#
Paywalls are versioned server-side. When you publish a change in the dashboard
or via POST /v1/apps/{app}/paywalls, every device picks it up on its next
fetch, with no App Store or Play review and no client release. Roll back just as fast
by re-publishing a previous version.
A/B experiments#
CashSDK can serve multiple paywall variants and split traffic between them. Each variant is measured on revenue per impression, so the winner accounts for both conversion rate and price, not clicks alone.
Duplicate a paywall and change one thing at a time (price emphasis, headline, trial length, layout).
Assign each variant a percentage of impressions. Customers are bucketed
deterministically by app_user_id so they always see the same variant.
Watch revenue per impression converge, then promote the winning variant to 100%. Everything happens over the air.
Targeting#
Serve different paywalls to different audiences without branching in your app. Target by:
- Country: localize pricing, currency framing, and offers per region.
- Platform: different layouts for iOS, Android, and Web.
- Cohort: segment by acquisition source, app version, or lifecycle stage (new install, lapsed, returning).
The SDK sends the customer's live attributes with each fetch, and CashSDK resolves the highest-priority matching paywall on the server.