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

dart
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,
  ),
]);
FieldTypeDescription
idStringRequired. Matches the plan/product ID used on the paywall screen in the editor.
priceStringRequired. Display price, already localized (e.g. from the store SDK).
priceAmount / currencyCodedouble? / String?Numeric price and ISO currency, used for analytics.
periodProductPeriod?week, month, year, or lifetime.
trialDays / trialEligibleint? / bool?Free-trial length and whether this user is eligible — drives trial copy on the screen.
originalPriceString?Pre-discount price for strike-through “was $119.99” treatments.
pricePerMonth / pricePerWeekString?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

dart
// 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,
    ),
]);