Skip to content

PaywallPlan, PaywallFeature and other paywall models

All six paywalls share these small, immutable data classes from dev.sanikant.m3.paywall. They hold display strings only. The library never talks to a billing provider, so you map your store data into them.

One purchasable option.

Property Type Default Description
id String required Your identifier. Returned in onPurchase so you can find the real product, offer token or package.
title String required Short name, e.g. “Yearly”.
price String required Formatted price from the store, e.g. “$29.99”.
period String required Shown after the price: “per year”, “per month”, “one-time”.
trialText String? null Trial terms, e.g. “7-day free trial”. null means no trial.
badge String? null Highlight such as “Best value”. The first badged plan is preselected.
priceDetail String? null Helper line, e.g. “$2.49/month, billed yearly”.
isSubscription Boolean true false for one-time purchases. Changes the disclosure to “one-time payment, no renewals”.
Monthly, yearly with trial, lifetime
val monthly = PaywallPlan(id = "pro_monthly", title = "Monthly", price = "$4.99", period = "per month")
val yearly = PaywallPlan(
id = "pro_yearly",
title = "Yearly",
price = "$29.99",
period = "per year",
trialText = "7-day free trial",
badge = "Best value",
priceDetail = "$2.49/month, billed yearly",
)
val lifetime = PaywallPlan(
id = "pro_lifetime",
title = "Lifetime",
price = "$79.99",
period = "one-time",
priceDetail = "Pay once, yours forever",
isSubscription = false,
)
val plans = listOf(monthly, yearly, lifetime)

The disclosure under the button is built from these fields:

  • with trialText: “7-day free trial, then $29.99 per year. Renews automatically until canceled. Cancel anytime in Google Play.”
  • subscription without trial: “$4.99 per month. Renews automatically until canceled. Cancel anytime in Google Play.”
  • isSubscription = false: “$79.99 one-time payment. No subscription, no renewals.”

PaywallFeature(title: String, description: String? = null, icon: ImageVector = PaywallIcons.Check), a benefit row.

val features = listOf(
PaywallFeature("Unlimited notes", "No caps on notes, folders or attachments", PaywallIcons.Sparkle),
PaywallFeature("Sync everywhere", "Phone, tablet and web, always up to date", PaywallIcons.Cloud),
PaywallFeature("Smart reminders", "Nudges at the right time and place", PaywallIcons.Bell),
PaywallFeature("Zero ads", "A calm space for your thoughts", PaywallIcons.Block),
)

PaywallLegal(termsUrl: String, privacyUrl: String), the links in every footer. They open through Compose’s LocalUriHandler.

val legal = PaywallLegal(
termsUrl = "https://your.app/terms",
privacyUrl = "https://your.app/privacy",
)

ComparisonRow(label: String, free: Boolean, pro: Boolean = true, freeText: String? = null, proText: String? = null), a row of the Free vs Pro table. Text replaces the check or cross icon when set.

val rows = listOf(
ComparisonRow("Notes", free = true, freeText = "50", proText = "Unlimited"),
ComparisonRow("Basic themes", free = true),
ComparisonRow("Cloud sync", free = false),
ComparisonRow("Smart reminders", free = false),
ComparisonRow("Ad-free", free = false),
)

TrialStep(title: String, description: String, icon: ImageVector), a step of the trial timeline.

BenefitPage(title: String, description: String, icon: ImageVector), a page of the onboarding carousel.

A small set of Material icons (Apache 2.0) bundled so the library needs no icon dependency: Check, Close, Remove, Sparkle, Star, Bolt, Bell, LockOpen, Cloud, Block, Shield, Calendar, Clock, Insights, Heart, Download. Any ImageVector works too, for example from material-icons-extended or your own vector drawables via ImageVector.vectorResource.

See the API reference for the full signatures.

Built by Sanikant. Set in Google Sans Flex (SIL Open Font License). Not affiliated with Google.