Skip to Content

Payment Flow

This guide walks through building a complete payment flow in a funnel — from product configuration to checkout to success page.

Overview

A payment flow has five parts:

  1. Configure products in funnel settings
  2. Add product selection UI (pricing page)
  3. Add the Payment Element component
  4. Add a submit button
  5. Configure the success page

Step 1: Configure Products

Products are configured in the funnel’s Settings > Products panel. Each product links a store price to a funnel-level ID that you reference in templates and click actions.

FieldDescription
IDInternal identifier used in product variables (e.g., monthly, yearly). Must be unique within the funnel.
NameDisplay name for the product. Accessible via products.{id}.displayName.
Store PriceThe imported store price to charge. Determines amount, currency, and billing interval.
Trial DaysOptional free trial period (in days). When set, the checkout captures the card without charging.
Trial PriceOptional one-time charge during the trial period (paid trial). A separate store price for the trial fee.
DefaultWhether this product is pre-selected when the funnel loads. Exactly one product should be marked as default.

Product Configuration Insert image: The Funnel Settings > Products panel showing two configured products with ID, name, store price dropdown, trial days, and default toggle fields

Product IDs are used in Liquid templates: {{ products.monthly.price }}, {{ products.yearly.periodly }}. Choose short, descriptive IDs.

Product Variables

Each configured product exposes computed variables for dynamic pricing display. Access them as products.{id}.{property} or products.selected.{property} for the currently selected product.

Common properties:

VariableExample OutputDescription
products.monthly.price$9.99Formatted price with currency symbol
products.monthly.rawPrice9.99Numeric price without symbol
products.monthly.periodmonthBilling period label
products.monthly.periodlymonthlyAdverbial form of the period
products.monthly.currencySymbol$Currency symbol
products.monthly.hasTrialtrueWhether the product has a trial
products.monthly.trialDays7Number of trial days
products.monthly.dailyPrice$0.33Price divided by period in days
products.monthly.weeklyPrice$2.30Price divided by period in weeks

For the full list of 39 product variable properties, see the Product Variable Reference.

Step 2: Add Product Selection UI

Visitors need a way to choose which product to purchase. Build pricing cards using Stacks with a Select Product click action on each one.

  1. Add a Stack for each product (e.g., “Monthly” and “Yearly” cards).
  2. On each Stack, add a click action: Select Product with the product ID.
  3. Add an Active Style condition to each Stack: products.selected.id equals monthly (or yearly). This highlights the selected plan automatically.
  4. Inside each Stack, use Text elements with Liquid templates to display pricing.

When a visitor taps a pricing card, the selectProduct action updates the selected product. All products.selected.* variables update reactively, so pricing text elsewhere on the page reflects the new selection.

Displaying Prices

Use Liquid templates in Text elements for dynamic pricing. Examples:

{{ products.yearly.price }}/{{ products.yearly.period }}
Save {{ products.yearly.rawPrice | divided_by: 12 | times: 100 | divided_by: products.monthly.rawPrice | minus: 100 | abs | round }}%
{{ products.selected.trialDays }}-day free trial, then {{ products.selected.price }}/{{ products.selected.period }}

Step 3: Add Payment Element

Add a Payment Element component to your checkout page. This renders the Stripe PaymentElement — a pre-built card form that supports cards, Apple Pay, Google Pay, and other payment methods.

Payment Element on Canvas Insert image: The editor canvas showing a checkout page with the Stripe Payment Element component rendered, displaying the card input form with a Submit button below

The Payment Element automatically uses the currently selected product to determine the payment amount and whether to create a PaymentIntent (direct charge) or SetupIntent (trial).

Trial detection is automatic. If the selected product has trial days configured, the Payment Element creates a SetupIntent to capture the card without charging. The subscription is created with the trial period after the card is saved. No extra configuration needed.

Alternative: Embedded Checkout (Stripe Managed)

Instead of the Payment Element, you can use the Embedded Checkout component. This renders Stripe’s complete checkout UI in an iframe — Stripe controls the entire payment experience.

Embedded Checkout uses Stripe Managed Payments. Stripe handles payment method selection, tax calculation, and compliance automatically. You don’t configure Apple Pay, Google Pay, or tax settings — Stripe decides what to show based on the customer’s location and device.

When to use Embedded Checkout over Payment Element:

Payment ElementEmbedded Checkout
UI controlFull — you style and position everythingStripe controls the UI
Payment methodsYou enable/disable individuallyStripe auto-selects optimal methods
TaxOptional (automaticTax flag)Stripe handles automatically
UpsellsSupports purchase action (saved card)No saved card for upsells
CustomizationStripe Appearance APILimited to Stripe’s design

Embedded Checkout does not save the card for future charges. If you need upsells after the initial purchase, use the Payment Element instead.

Step 4: Add Submit Button

Add a button (or any clickable component) with the Submit Payment Element click action. This triggers form validation and payment submission.

Typical setup:

  1. Add a Stack or Button component below the Payment Element.
  2. Add click action: Submit Payment Element.
  3. Optionally add an onFailure chain to handle errors (e.g., set a variable to display an error message).

Payment State Variables

During checkout, these system variables update automatically:

VariableTypeDescription
payment.loadingbooleantrue while payment is being processed
payment.errorstringError message if payment fails, empty otherwise
purchase.statusstringCurrent purchase status
purchase.successbooleantrue after successful payment
purchase.amountnumberCharged amount
purchase.currencystringCurrency code

Use payment.loading for button loading states and payment.error for error display via dynamic properties or Liquid templates.

Step 5: Configure Success Page

After a successful payment, the visitor needs to navigate to a success page (download, confirmation, etc.).

Two approaches:

  1. Route-based — Configure the checkout page’s route to point to the success page. Add “Go to Next Page” as a click action after “Submit Payment Element” in the action chain. The route evaluates after payment succeeds.

  2. Conditional navigation — Use a dynamic property on the “Go to Next Page” action, conditioned on purchase.success == true.

A paid trial charges a small upfront fee while signing the customer up for a subscription that starts after the trial period. This is implemented by combining a one-time product (the trial fee) with a subscription product (the recurring plan).

How It Works

When you configure a product with both a Store Price (the subscription) and a Trial Price (a separate one-time price), AppFunnel:

  1. Charges the trial price immediately as a one-time payment
  2. Creates the subscription with the trial period — the first renewal happens after the trial days expire
  3. The card is captured from the trial payment, so no additional payment form is needed for the subscription

Example: 1-Week Trial

FieldValue
Store PriceYearly subscription — $39.99/year
Trial Days7
Trial PriceOne-time price — $4.99

The visitor pays $4.99 upfront. After 7 days, their subscription renews at $39.99/year.

Display this in your funnel with Liquid:

{{ products.selected.trialDays }}-day trial: {{ products.selected.trialPrice }}
Renews at {{ products.selected.price }}/{{ products.selected.period }}

More Examples

OfferTrial PriceTrial DaysSubscription
1-week trial: $4.99 (renews at $39.99/yr)$4.99 one-time7$39.99/year
3-day trial: $0.99 (renews at $9.99/mo)$0.99 one-time3$9.99/month
14-day trial: $1.99 (renews at $19.99/mo)$1.99 one-time14$19.99/month

Setup

Create Two Prices in Stripe

Create a recurring price for the subscription (e.g., $39.99/year) and a one-time price for the trial fee (e.g., $4.99). Import both into AppFunnel via your store.

Configure the Product

In Funnel Settings > Products, set the Store Price to the recurring price, enter the Trial Days, and set the Trial Price to the one-time price.

Display Trial Pricing

Use product variables to show the trial offer on your pricing page:

Start for just {{ products.yearly.trialPrice }} — {{ products.yearly.trialDays }}-day trial, then {{ products.yearly.price }}/{{ products.yearly.period }}

The products.{id}.paidTrial variable is true when a product has a trial price configured. Use it for conditional display:

{% if products.selected.paidTrial %} {{ products.selected.trialDays }}-day trial for {{ products.selected.trialPrice }} {% elsif products.selected.hasTrial %} {{ products.selected.trialDays }}-day free trial {% endif %}

Complete Example

A typical payment funnel flow:

Quiz Pages --> Pricing Page --> Checkout Page --> Success Page | | selectProduct submitPaymentElement (per option) (on submit button)

Pricing page shows plan cards with products.monthly.price and products.yearly.price in text elements. Each card (Stack) has a selectProduct click action and an Active Style condition to highlight the selected plan.

Checkout page contains an email Input (bound to user.email), the Payment Element, and a submit button. The submit button has two chained actions: submitPaymentElement followed by goToNextPage.

Success page shows a confirmation message using {{ products.selected.displayName }} and routes to the app download page.

The visitor must provide an email before payment. The Payment Element requires a customer email to create the Stripe Customer. Capture the email on a prior page or on the checkout page itself using an Input element bound to user.email.

Last updated on