Build a multi-seller digital marketplace where sellers upload products with preview files and encrypted download paths. Buyers purchase through Stripe Connect which splits payment between platform and seller. A Cloud Function generates time-limited signed download URLs only for verified purchasers. Seller dashboards track earnings, downloads, and product performance.
Building a Multi-Seller Digital Product Marketplace in FlutterFlow
A digital marketplace differs from physical e-commerce in one critical way: delivery is instant via download. This means securing download URLs, splitting payments between platform and sellers, and handling the full seller lifecycle from product upload to earnings payout. This tutorial covers each piece using FlutterFlow, Firestore, Cloud Functions, and Stripe Connect.
Prerequisites
- A FlutterFlow project with Firestore and Firebase Authentication configured
- A Stripe account with Connect enabled and platform settings configured
- Firebase Blaze plan for Cloud Functions and Storage
- Firebase Storage configured with security rules restricting direct access to product files
Step-by-step guide
Design the Firestore data model for products, sellers, and purchases
Design the Firestore data model for products, sellers, and purchases
Create a sellers collection with fields: userId (Reference), storeName (String), storeDescription (String), stripeAccountId (String, from Stripe Connect onboarding), rating (Double), totalEarnings (Double), isVerified (Boolean). Create products with: sellerId (Reference to sellers), title (String), description (String), price (Double), category (String), previewUrl (String, public preview image or sample), fileStoragePath (String, private path to actual downloadable file), downloadCount (Int), rating (Double), ratingCount (Int), status (String: active/paused/removed), createdAt (Timestamp). Create purchases with: buyerId (Reference), productId (Reference), sellerId (Reference), price (Double), platformFee (Double), sellerPayout (Double), stripePaymentIntentId (String), downloadUrl (String, signed URL), downloadExpiresAt (Timestamp), purchasedAt (Timestamp).
Expected result: Firestore has a complete relational model for products, sellers, and purchases with clear separation of public previews and private download files.
Build the product catalog with category filters and search
Build the product catalog with category filters and search
Create a BrowseProductsPage with a top Row containing a search TextField and a category ChoiceChips widget (All, Templates, Ebooks, Courses, Design Assets, Music). Below, display a GridView with crossAxisCount of 2 querying products where status is active. Apply category filter via Conditional Backend Query. Each grid cell is a Container card showing the preview image (Image widget from previewUrl), product title (Text, bodyLarge, maxLines 2), seller store name (Text, bodySmall), price (Text, bold), and a Row with star rating and download count. Tapping a card navigates to the ProductDetailPage passing the product document reference.
Expected result: Buyers can browse all active products in a responsive grid, filter by category, and tap to view product details.
Set up Stripe Connect onboarding for sellers and payment splitting
Set up Stripe Connect onboarding for sellers and payment splitting
Create a BecomeSellerPage with store name and description TextFields. On Submit, create the seller doc in Firestore. Then call a Cloud Function createStripeConnectAccount(userId) that creates a Stripe Express Connected Account via the Stripe API, stores the stripeAccountId on the seller doc, and returns an onboarding link URL. Open the onboarding link for the seller to complete identity verification and bank details. On the product detail page Buy Now button, call a Cloud Function createDigitalPurchase(productId, buyerId). This function creates a Stripe Payment Intent with transfer_data specifying the seller's stripeAccountId and an application_fee_amount (e.g., 15% platform fee). Return the Checkout URL to the client.
Expected result: Sellers complete Stripe Connect onboarding, and purchases automatically split payment between the platform fee and seller payout.
Generate secure time-limited signed download URLs after purchase
Generate secure time-limited signed download URLs after purchase
In the Stripe webhook handler Cloud Function for checkout.session.completed, find the corresponding product and buyer. Use the Firebase Admin SDK to generate a signed URL for the product's fileStoragePath with a 15-minute expiry: bucket.file(storagePath).getSignedUrl({ action: 'read', expires: Date.now() + 15 * 60 * 1000 }). Store the signed URL and its expiry in the purchase document. On the My Purchases page, query purchases for the current user. For each purchase, check if downloadExpiresAt is in the future. If yes, show a Download button that opens the URL. If expired, show a Regenerate Link button that calls a Cloud Function to generate a fresh signed URL (verifying the purchase still exists).
Expected result: Buyers receive time-limited download links after payment, with the ability to regenerate expired links for verified purchases.
Build the seller dashboard with product management and earnings tracking
Build the seller dashboard with product management and earnings tracking
Create a SellerDashboardPage with a TabBar: Products, Earnings, Settings. Products tab: ListView querying products where sellerId equals the current seller, with Add Product FAB. Add Product opens a form with title, description, price, category DropDown, preview image upload (FlutterFlowUploadButton to public Storage path), and product file upload (FlutterFlowUploadButton to private Storage path). Earnings tab: display totalEarnings in a large Text widget, a monthly earnings chart (Custom Widget with fl_chart), and a ListView of recent purchases showing product name, buyer, amount, and date. Settings tab: store name editor, payout schedule info, and a link to Stripe Express dashboard for payout management.
Expected result: Sellers can manage their product catalog, upload new products, track sales and earnings, and access their Stripe payout dashboard.
Complete working example
1FIRESTORE DATA MODEL:2 sellers/{sellerId}3 userId: Reference (users)4 storeName: String5 storeDescription: String6 stripeAccountId: String7 rating: Double8 totalEarnings: Double9 isVerified: Boolean1011 products/{productId}12 sellerId: Reference (sellers)13 title: String14 description: String15 price: Double16 category: String (Templates | Ebooks | Courses | Design Assets | Music)17 previewUrl: String (public Storage URL)18 fileStoragePath: String (private, e.g., 'products/private/seller123/file.zip')19 downloadCount: Int20 rating: Double21 ratingCount: Int22 status: String (active | paused | removed)23 createdAt: Timestamp2425 purchases/{purchaseId}26 buyerId: Reference (users)27 productId: Reference (products)28 sellerId: Reference (sellers)29 price: Double30 platformFee: Double (15%)31 sellerPayout: Double (85%)32 stripePaymentIntentId: String33 downloadUrl: String (signed, 15-min expiry)34 downloadExpiresAt: Timestamp35 purchasedAt: Timestamp3637STORAGE RULES:38 products/public/{sellerId}/{file} → allow read if authenticated39 products/private/{sellerId}/{file} → deny all client reads40 (only Cloud Functions generate signed URLs)4142PAGE: BrowseProductsPage43 Column44 Row: TextField (search) + ChoiceChips (categories)45 GridView (crossAxisCount: 2, padding: 8)46 Backend Query: products where status==active, filtered by category47 Card48 Image (previewUrl, fit: cover, height: 140)49 Padding Column50 Text (title, bodyLarge, maxLines: 2)51 Text (storeName, bodySmall, grey)52 Row: Text (price, bold) + Row(star icon + rating + downloadCount)53 On Tap → Navigate ProductDetailPage5455PAGE: SellerDashboardPage56 TabBar: Products | Earnings | Settings57 Products Tab:58 ListView: seller's products with edit/pause/delete actions59 FAB → Add Product form60 Earnings Tab:61 Text (totalEarnings, headlineLarge, green)62 Custom Widget (monthly earnings LineChart)63 ListView (recent sales)Common mistakes when creating a Marketplace for Digital Products in FlutterFlow
Why it's a problem: Storing digital product files at publicly accessible Firebase Storage URLs
How to avoid: Store product files in a private Storage path with security rules that deny all client reads. Generate time-limited signed URLs via Cloud Function only for verified purchasers.
Why it's a problem: Using a single Stripe account for all marketplace payments instead of Stripe Connect
How to avoid: Set up Stripe Connect with Express accounts per seller. Payment Intents use transfer_data and application_fee_amount to automatically split funds.
Why it's a problem: Generating download URLs with no expiry or very long expiry times
How to avoid: Generate signed URLs with 15-minute expiry. Allow buyers to regenerate links from the My Purchases page, verified against their purchase record each time.
Best practices
- Use Stripe Connect Express accounts so sellers handle their own tax reporting and payout management
- Set signed URL expiry to 15 minutes and allow regeneration to balance security with usability
- Store preview files in a public Storage path and product files in a private path with deny-all client rules
- Increment downloadCount atomically in the Cloud Function when generating a download URL
- Add product ratings by creating a reviews subcollection and recalculating the average in a Cloud Function on each new review
- Show sellers their pending balance versus paid-out balance using Stripe's Balance API
- Validate uploaded product files (size limits, allowed file types) in the Cloud Function before accepting the upload
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a multi-seller digital product marketplace in FlutterFlow. Show me the Firestore data model, Stripe Connect setup for payment splitting, signed download URL generation, and the seller dashboard with earnings tracking.
Create a product browsing page with a search bar and category chips at the top. Below, add a 2-column grid of product cards, each showing a preview image, title, seller name, price, and star rating. Add a floating action button for sellers to add new products.
Frequently asked questions
How do I prevent buyers from sharing download links?
Signed URLs expire after 15 minutes, limiting sharing windows. For additional protection, watermark digital files with the buyer's name or email in the Cloud Function before generating the download URL.
What percentage should I take as a platform fee?
Digital marketplace platform fees typically range from 10-30%. Stripe Connect lets you set the application_fee_amount per transaction. Start at 15% and adjust based on seller feedback and competition.
Can sellers offer free products on the marketplace?
Yes. For free products, skip the Stripe payment step. On the Download button, directly call the Cloud Function to generate a signed URL. Still create a purchase record in Firestore with price 0 for download tracking.
How do I handle refunds for digital products?
Create a Cloud Function that calls Stripe's refund API, reversing the transfer to the seller. Update the purchase status to refunded and invalidate any active download URLs by deleting the downloadUrl field.
Can I add product reviews and ratings?
Yes. Create a reviews subcollection under each product with buyerId, rating (1-5), comment, and timestamp. Write a Cloud Function that recalculates the average rating on the product doc whenever a new review is added.
What if I need help building a production-ready digital marketplace?
RapidDev has built multi-seller marketplaces in FlutterFlow with Stripe Connect, automated payouts, content protection, review systems, and seller analytics. They can handle the complex payment and delivery infrastructure.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation