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.
Fetch and render with the SDK#
The SDK fetches the current paywall configuration and its offering. You render
your UI from that data and hand a package to purchase.
let offering = try await CashSDK.offerings()
// Render your paywall from offering.paywall + offering.packages
let result = try await CashSDK.purchase(offering.monthly)
if result.entitlements["pro"]?.isActive == true {
unlockPro()
}
val offering = CashSDK.offerings()
val result = CashSDK.purchase(offering.monthly)
if (result.entitlements["pro"]?.isActive == true) {
unlockPro()
}
const offering = await CashSDK.offerings();
const result = await CashSDK.purchase(offering.monthly);
if (result.entitlements["pro"]?.isActive) {
unlockPro();
}
Fetch offerings early (for example on app launch) and cache the result. 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 — no App Store or Play review, 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.