Flutter SDK / Products & paywalls
Products & paywalls
Paywall screens are designed in the dashboard, but prices belong to the stores. Register your products once and every paywall shows real, localized pricing — no hardcoded strings in your flow.
Register your catalog
await UpliftFunnel.setProducts([
UpliftFunnelProduct(
id: 'yearly_pro',
price: '\$59.99',
priceAmount: 59.99,
currencyCode: 'USD',
period: ProductPeriod.year,
trialDays: 7,
originalPrice: '\$119.99', // for strike-through pricing
pricePerMonth: '\$5.00',
pricePerWeek: '\$1.15',
),
UpliftFunnelProduct(
id: 'monthly_pro',
price: '\$9.99',
priceAmount: 9.99,
currencyCode: 'USD',
period: ProductPeriod.month,
),
]);| Field | Type | Description |
|---|---|---|
| id | String | Required. Matches the plan/product ID used on the paywall screen in the editor. |
| price | String | Required. Display price, already localized (e.g. from the store SDK). |
| priceAmount / currencyCode | double? / String? | Numeric price and ISO currency, used for analytics. |
| period | ProductPeriod? | week, month, year, or lifetime. |
| trialDays / trialEligible | int? / bool? | Free-trial length and whether this user is eligible — drives trial copy on the screen. |
| originalPrice | String? | Pre-discount price for strike-through “was $119.99” treatments. |
| pricePerMonth / pricePerWeek | String? | Broken-down prices for “only $5/mo” framing on annual plans. |
How screens consume products
Each field fans out into flow variables named <field>.<productId>, so editor copy can interpolate them anywhere:
{{price.yearly_pro}}→$59.99{{price_per_month.yearly_pro}}→$5.00{{trial_days.yearly_pro}}→7
plan_picker screens bind automatically: plans whose IDs match your registered products pick up live prices, periods, and trial copy without any per-screen setup. When the user confirms, your purchase handler receives the selected planId and the platform-resolved productId.
Sourcing prices from your billing SDK
// Feed real store pricing from RevenueCat offerings.
final offerings = await Purchases.getOfferings();
final packages = offerings.current?.availablePackages ?? [];
await UpliftFunnel.setProducts([
for (final pkg in packages)
UpliftFunnelProduct(
id: pkg.identifier,
price: pkg.storeProduct.priceString, // localized by the store
priceAmount: pkg.storeProduct.price,
currencyCode: pkg.storeProduct.currencyCode,
),
]);