Build a multi-step checkout flow using PageView with four steps: cart review (item list with quantity adjustment), shipping address form (validated fields), payment via Stripe Checkout redirect, and order confirmation. Use App State for persistent cart data. Step indicators show progress. Each step validates before allowing Continue. Calculate subtotal, tax, and total with Custom Functions. Redirect to Stripe Checkout Session from a Cloud Function on Place Order.
Building a Multi-Step Checkout Flow in FlutterFlow
A checkout flow converts browsers into buyers. Breaking it into clear steps (cart, shipping, payment, confirmation) reduces abandonment and gives users confidence about each part of the process. This tutorial builds the complete flow with validation and Stripe integration.
Prerequisites
- FlutterFlow Pro plan (Cloud Functions for Stripe)
- Stripe account with test mode API keys
- App State configured for cart management
- Firestore orders collection
Step-by-step guide
Set up App State for persistent cart management
Set up App State for persistent cart management
Add an App State variable cartItems (JSON List type, persisted). Each item is a JSON object: {productId, name, price, quantity, imageUrl}. Persisting ensures the cart survives navigation and app restarts. Add Custom Functions: addToCart (adds item or increments quantity), removeFromCart (removes item), updateQuantity (changes quantity), calculateSubtotal (sum of price * quantity), calculateTax (subtotal * 0.08), calculateTotal (subtotal + tax).
Expected result: Cart state persists across pages with functions for manipulation and calculation.
Build the cart review step with quantity adjusters
Build the cart review step with quantity adjusters
Step 1 of the PageView: a Column with ListView bound to cartItems. Each item Row shows: Image (50x50), Column (name, price), Row (minus IconButton, quantity Text, plus IconButton). Minus/plus buttons call updateQuantity Custom Function. Below the list: Divider, Row for Subtotal, Row for Tax, Row for Total (bold). The Continue button is disabled if cartItems is empty.
Expected result: Cart review shows all items with adjustable quantities and calculated totals.
Build the shipping address form with field validation
Build the shipping address form with field validation
Step 2: a Column with TextFields for Full Name, Street Address, City, State, and Zip Code. Add validation: all fields required, zip code must be 5 digits (regex). Store values in Page State or a formData Map. The Continue button validates all fields before advancing — show red error text below any field that fails validation. Pre-fill fields from the user document if a saved address exists.
Expected result: A validated shipping form that blocks advancement until all fields are correctly filled.
Trigger Stripe Checkout on the Place Order step
Trigger Stripe Checkout on the Place Order step
Step 3 shows an order summary (items + shipping address + total) and a Place Order button. On tap: call the Cloud Function that creates a Stripe Checkout Session with the cart items. On success: receive the session URL → Launch URL to redirect to Stripe. Also create a pending order document in Firestore (status: pending, items, address, total). The Stripe webhook updates the order status to paid on successful payment.
Expected result: Place Order creates a pending order and redirects to Stripe Checkout for payment.
Show order confirmation after Stripe redirect
Show order confirmation after Stripe redirect
Configure the Stripe success_url to redirect back to your app's confirmation page with the orderId as a parameter. Step 4 (or a separate ConfirmationPage): fetch the order document, show the success animation, order details, and reference number. Clear the cartItems App State after successful payment confirmation.
Expected result: After payment, users see the confirmation page and the cart is cleared.
Complete working example
1APP STATE:2 cartItems: JSON List (persisted) = []3 Each item: {productId, name, price, quantity, imageUrl}45CUSTOM FUNCTIONS:6 addToCart(item) → adds or increments7 removeFromCart(productId) → removes item8 updateQuantity(productId, newQty) → updates9 calculateSubtotal() → sum(price * quantity)10 calculateTax(subtotal) → subtotal * 0.0811 calculateTotal(subtotal, tax) → subtotal + tax1213CHECKOUT PAGE:14 Row (step indicators: 1-Cart 2-Shipping 3-Payment 4-Done)15 PageView (4 steps, NeverScrollableScrollPhysics)1617STEP 1 — CART REVIEW:18 ListView (cartItems) → item rows with qty +/-19 Subtotal / Tax / Total rows20 Button "Continue" (disabled if cart empty)2122STEP 2 — SHIPPING:23 TextFields: name, address, city, state, zip24 Validation on each field25 Button "Continue" (validates before advancing)2627STEP 3 — PAYMENT:28 Order summary (items + address + total)29 Button "Place Order"30 → Cloud Function → Stripe Checkout Session31 → Create pending order in Firestore32 → Launch URL → Stripe hosted page3334STEP 4 — CONFIRMATION:35 Lottie checkmark + order details + reference36 Clear cartItems App StateCommon mistakes when creating a Custom Checkout Screen for Your FlutterFlow App
Why it's a problem: Storing cart in Page State instead of App State
How to avoid: Use App State with persistence enabled for cart data so it survives navigation and app restarts.
Why it's a problem: Not validating shipping fields before the payment step
How to avoid: Validate all required fields (non-empty, zip format) on the Continue button before advancing to the payment step.
Why it's a problem: Trusting client-side price calculations for payment
How to avoid: Have the Cloud Function look up actual product prices from your database and calculate the total server-side.
Best practices
- Store cart in persistent App State to survive navigation and restarts
- Validate each step before allowing advancement to the next
- Calculate final prices server-side in the Cloud Function, not client-side
- Use step indicators to show progress through the checkout flow
- Pre-fill shipping fields from saved user addresses when available
- Create a pending order in Firestore before redirecting to Stripe
- Clear the cart after confirmed successful payment
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Build a multi-step checkout in FlutterFlow with cart review, shipping form, Stripe payment, and confirmation. Use App State for cart, PageView for steps, and a Cloud Function for Stripe Checkout Session. Show the complete flow.
Create a page with a step indicator row at top (4 circles with labels), a PageView below filling the remaining space, and navigation buttons at the bottom.
Frequently asked questions
Can I add a coupon code field?
Yes. Add a TextField and Apply button on the cart step. Create a Cloud Function that validates the coupon code against a Firestore promotions collection and returns the discount. Apply the discount to the subtotal calculation.
How do I save the user's shipping address for next time?
On successful order, save the shipping address to the user's Firestore document. On the shipping step, pre-fill fields from the saved address if it exists.
Can I add guest checkout without login?
Yes. Skip the userId field and use a session identifier. Collect an email address on the shipping form for order confirmation emails.
How do I handle Stripe Checkout cancellation?
Stripe redirects to cancel_url when the user clicks Back. On your checkout page, show a message that payment was not completed and allow retry.
Can I support multiple payment methods?
Stripe Checkout supports cards, Apple Pay, Google Pay, PayPal, and more. Enable them in your Stripe Dashboard under Payment Methods.
Can RapidDev help build e-commerce checkout?
Yes. RapidDev can build complete e-commerce flows including cart management, checkout, payment, order management, shipping integration, and inventory tracking.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation