Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Monitor Your FlutterFlow App's Payments

Effective payment monitoring combines Stripe Dashboard for financial metrics with Firestore order sync for in-app status displays. Use Stripe webhooks to write order records to Firestore after payment succeeds. Build a simple revenue dashboard with fl_chart in a Custom Widget. Set up Stripe email alerts for failed payments and refunds. Monitoring both systems lets you catch issues fast and show payment status to your users.

What you'll learn

  • How to use Stripe Dashboard to monitor revenue and failed payments
  • How to sync Stripe payment events to Firestore via webhooks
  • How to display payment status to users inside your FlutterFlow app
  • How to set up automated alerts for payment failures and refunds
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner8 min read30-45 minFlutterFlow Pro+ (code export required for Custom Widget charts)March 2026RapidDev Engineering Team
TL;DR

Effective payment monitoring combines Stripe Dashboard for financial metrics with Firestore order sync for in-app status displays. Use Stripe webhooks to write order records to Firestore after payment succeeds. Build a simple revenue dashboard with fl_chart in a Custom Widget. Set up Stripe email alerts for failed payments and refunds. Monitoring both systems lets you catch issues fast and show payment status to your users.

Why You Need Two Payment Monitoring Systems

Stripe Dashboard is the source of truth for your money — it shows every charge, payout, refund, and dispute. But your users can't see Stripe Dashboard. They need to see payment confirmation inside your app. This requires syncing Stripe events to Firestore via webhooks and displaying the order status from Firestore. The two systems serve different purposes: Stripe for your business metrics, Firestore for your users' experience. Setting up both takes under an hour and prevents the most common payment support complaints — 'I paid but nothing happened' and 'where is my order?'

Prerequisites

  • A Stripe account with at least one test payment made
  • A FlutterFlow project with Firebase and Firestore connected
  • A Cloud Function deployed for your payment flow (or Stripe Checkout sessions)
  • FlutterFlow Pro plan for Custom Widget (Standard works for basic order status display)

Step-by-step guide

1

Configure Stripe Dashboard Metrics and Alerts

Log in to dashboard.stripe.com. The Home tab shows your key metrics: gross volume, net volume, successful payment rate, and dispute rate. Navigate to Payments > Reports to access Revenue, Payouts, and Reconciliation reports. Enable email alerts by going to Settings > Email Notifications and enabling: failed payments, disputes, refunds, and successful payouts. Set a spend threshold alert at Settings > Billing Alerts so you know when you hit monthly revenue milestones. Bookmark the Stripe Radar dashboard (Radar > Overview) if you're in a fraud-prone category — it shows suspicious activity patterns.

Expected result: You receive email alerts for every payment failure, dispute, and refund, and can see key revenue metrics on the Stripe Dashboard home screen.

2

Create a Firestore Orders Collection for Payment Sync

In FlutterFlow, open your Firestore schema and create an 'orders' collection with these fields: userId (String), productId (String), amount (double), currency (String), status (String — values: pending, paid, failed, refunded), stripePaymentIntentId (String), stripeSessionId (String), createdAt (Timestamp), paidAt (Timestamp, nullable). This schema lets you display order history to users and track payment status without exposing Stripe details. The stripePaymentIntentId and stripeSessionId fields let you look up the corresponding Stripe event for any order, which is essential for debugging payment disputes.

Expected result: An 'orders' collection is defined in your FlutterFlow Firestore schema and ready to receive data from your payment webhook.

3

Deploy a Stripe Webhook Cloud Function to Sync Orders

In Firebase Console, go to Functions and create a new Cloud Function. This function receives Stripe webhook events and writes order records to Firestore. Register the webhook endpoint URL in Stripe at Dashboard > Developers > Webhooks. Listen for these events: checkout.session.completed (creates the order document), payment_intent.payment_failed (updates status to failed), charge.refunded (updates status to refunded). Always verify the Stripe webhook signature using the webhook secret — this prevents attackers from faking payment success events.

stripe_webhook_function.js
1const functions = require('firebase-functions');
2const admin = require('firebase-admin');
3const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
4
5exports.stripeWebhook = functions.https.onRequest(async (req, res) => {
6 const sig = req.headers['stripe-signature'];
7 let event;
8 try {
9 event = stripe.webhooks.constructEvent(
10 req.rawBody,
11 sig,
12 process.env.STRIPE_WEBHOOK_SECRET
13 );
14 } catch (err) {
15 console.error('Webhook signature verification failed:', err.message);
16 return res.status(400).send(`Webhook Error: ${err.message}`);
17 }
18
19 const db = admin.firestore();
20
21 if (event.type === 'checkout.session.completed') {
22 const session = event.data.object;
23 await db.collection('orders').add({
24 userId: session.metadata.userId,
25 productId: session.metadata.productId,
26 amount: session.amount_total / 100,
27 currency: session.currency,
28 status: 'paid',
29 stripeSessionId: session.id,
30 createdAt: admin.firestore.FieldValue.serverTimestamp(),
31 paidAt: admin.firestore.FieldValue.serverTimestamp(),
32 });
33 }
34
35 if (event.type === 'payment_intent.payment_failed') {
36 const intent = event.data.object;
37 await db.collection('orders')
38 .where('stripePaymentIntentId', '==', intent.id)
39 .get()
40 .then(snapshot => {
41 snapshot.forEach(doc => {
42 doc.ref.update({
43 status: 'failed',
44 errorMessage: intent.last_payment_error?.message || 'Payment failed',
45 });
46 });
47 });
48 }
49
50 res.json({ received: true });
51});

Expected result: Stripe payment events automatically create or update order documents in Firestore within seconds of the payment completing.

4

Display Order History and Payment Status in Your App

In FlutterFlow, create an Order History page. Add a ListView with a Firestore query on the 'orders' collection filtered by userId == currentUserUID and ordered by createdAt descending. In each list item, display: amount formatted as currency, product name (look up from productId or denormalize the name into the order document), paidAt date, and a status badge. Style the status badge with conditional colors: green Container for 'paid', red for 'failed', orange for 'pending', grey for 'refunded'. This gives users a clear view of their payment history and resolves the most common support question — 'did my payment go through?'

Expected result: Users see a list of their orders with status badges, amounts, and dates — with paid orders showing green and failed orders showing red.

5

Set Up Revenue Dashboard with Key Metrics

For your admin or personal tracking, create a Payment Analytics page visible only to users with an 'admin' role. Use Firestore aggregate queries (via a Custom Action) to calculate: total revenue (sum of amount where status == paid), order count, average order value, and failure rate. Display these in metric cards using a Row of stat containers. For a simple revenue chart showing daily totals, use fl_chart in a Custom Widget — add fl_chart as a package dependency in your project settings. Alternatively, embed a Stripe Dashboard link in an iFrame for web deployments (Stripe allows this for internal tools).

Expected result: An admin page shows total revenue, order count, and failure rate — giving you a quick pulse on payment health without opening Stripe Dashboard.

Complete working example

order_status_widget.dart
1// Custom Function: Format order amount for display
2String formatOrderAmount(double amount, String currency) {
3 final formatter = NumberFormat.currency(
4 symbol: currency.toUpperCase() == 'USD' ? '\$' : currency.toUpperCase() + ' ',
5 decimalDigits: 2,
6 );
7 return formatter.format(amount);
8}
9
10// Custom Function: Get status badge color
11Color getStatusColor(String status) {
12 switch (status.toLowerCase()) {
13 case 'paid':
14 return const Color(0xFF22C55E); // green-500
15 case 'pending':
16 return const Color(0xFFF59E0B); // amber-500
17 case 'failed':
18 return const Color(0xFFEF4444); // red-500
19 case 'refunded':
20 return const Color(0xFF6B7280); // gray-500
21 default:
22 return const Color(0xFF6B7280);
23 }
24}
25
26// Custom Function: Get status display label
27String getStatusLabel(String status) {
28 switch (status.toLowerCase()) {
29 case 'paid':
30 return 'Payment Successful';
31 case 'pending':
32 return 'Processing';
33 case 'failed':
34 return 'Payment Failed';
35 case 'refunded':
36 return 'Refunded';
37 default:
38 return 'Unknown';
39 }
40}
41
42// Custom Function: Format order date
43String formatOrderDate(DateTime? timestamp) {
44 if (timestamp == null) return 'Date unknown';
45 return DateFormat('MMM d, yyyy \'at\' h:mm a').format(timestamp);
46}

Common mistakes when monitoring Your FlutterFlow App's Payments

Why it's a problem: Relying only on Stripe Dashboard without syncing to Firestore

How to avoid: Deploy the webhook Cloud Function to sync every checkout.session.completed event to a Firestore 'orders' document. This creates the user-facing payment record automatically.

Why it's a problem: Not verifying the Stripe webhook signature

How to avoid: Always use stripe.webhooks.constructEvent() with your webhook secret. This cryptographically verifies the event came from Stripe.

Why it's a problem: Calculating revenue aggregates from Firestore on every page load

How to avoid: Use a scheduled Cloud Function to pre-calculate aggregates (daily revenue, order count) and store them in a single 'metrics' document. Display that document on your admin page.

Best practices

  • Always verify Stripe webhook signatures — never trust unsigned payment events
  • Denormalize product names and user emails into order documents to reduce additional Firestore reads
  • Store Stripe payment intent IDs and session IDs in orders so you can cross-reference with Stripe Dashboard
  • Set up Stripe email alerts for failed payments, disputes, and refunds on day one
  • Use Firestore security rules to ensure users can only read their own orders
  • Test your webhook with the Stripe CLI before deploying to production
  • Set up budget alerts in Firebase Console to catch unexpected Firestore read spikes from payment queries

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I have a FlutterFlow app with Stripe Checkout integration. I want to set up payment monitoring so: (1) I get notified of failed payments, (2) users can see their order history in the app, and (3) I have a simple admin view of daily revenue. Walk me through the Firebase Cloud Functions and Firestore schema I need to make this work.

FlutterFlow Prompt

In my FlutterFlow project, create a Custom Action called 'fetchOrderSummary' that queries the 'orders' Firestore collection for the current user, calculates the total amount paid (sum of amount field where status == 'paid'), and returns it as a double. Use the FlutterFlow Firestore helper to make the query.

Frequently asked questions

How do I know if a Stripe payment succeeded in my FlutterFlow app?

The most reliable method is a Stripe webhook: Stripe POSTs a checkout.session.completed event to your Cloud Function, which creates an order document in Firestore with status 'paid'. Your app queries this document to confirm payment. Never rely on URL parameters from Stripe's success redirect URL, as users can manipulate them.

Can I display Stripe payment status directly in FlutterFlow without a backend?

No. Stripe's API requires your secret key, which must never be in client-side code. You must use a Cloud Function or server to call Stripe and return the status. The Cloud Function creates an order record in Firestore, which FlutterFlow then reads directly — that is safe.

How do I handle failed payments in my FlutterFlow app?

Listen for the payment_intent.payment_failed Stripe webhook event in your Cloud Function. Update the corresponding order document's status to 'failed' and store the error message from intent.last_payment_error.message. Display a clear message to the user with the failure reason and a link to retry payment.

What Stripe Dashboard metrics should I check daily?

Check gross volume (total revenue), successful payment rate (anything below 95% needs investigation), dispute rate (above 0.5% risks losing Stripe access), and payout status (to confirm funds are arriving in your bank account on schedule).

How do I handle refunds in my FlutterFlow app?

Issue refunds from Stripe Dashboard (Payments > select payment > Refund). Listen for the charge.refunded webhook event in your Cloud Function and update the order document's status to 'refunded'. Show the refunded status in your order history so users can see it without contacting support.

Is it safe to store Stripe payment intent IDs in Firestore?

Yes. Payment intent IDs (pi_xxx) and session IDs (cs_xxx) are not sensitive — they're identifiers, not credentials. Storing them in Firestore lets you cross-reference Firestore orders with Stripe Dashboard events for debugging and dispute resolution. Never store secret keys or full card details.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.