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

How to Set Up a Virtual Wallet for In-App Currency in FlutterFlow

Build an in-app currency wallet with a Firestore-backed balance system, transaction history, and coin purchase packs. The wallet displays the current coin balance with an animated counter, logs every earn and spend event in a transaction subcollection, lets users buy coin packs via Stripe, claim daily bonuses with streak multipliers, and spend coins in an in-app store. All balance modifications go through Cloud Functions to prevent client-side manipulation.

What you'll learn

  • How to design a Firestore schema for virtual currency with balance and transaction history
  • How to build a wallet UI with animated balance display and transaction feed
  • How to implement coin purchase packs via Stripe Cloud Functions
  • How to set up daily bonus rewards with streak multipliers
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner9 min read25-30 minFlutterFlow Pro+ (Cloud Functions required for secure transactions)March 2026RapidDev Engineering Team
TL;DR

Build an in-app currency wallet with a Firestore-backed balance system, transaction history, and coin purchase packs. The wallet displays the current coin balance with an animated counter, logs every earn and spend event in a transaction subcollection, lets users buy coin packs via Stripe, claim daily bonuses with streak multipliers, and spend coins in an in-app store. All balance modifications go through Cloud Functions to prevent client-side manipulation.

Building a Virtual Wallet for In-App Currency in FlutterFlow

In-app currencies drive engagement in gaming, education, and social apps. This tutorial builds the wallet experience: a visually appealing balance card with coin animations, a full transaction history, purchasable coin packs via Stripe, a daily bonus with streak multipliers, and a spend flow for an in-app store. All balance changes are server-side to prevent cheating.

Prerequisites

  • A FlutterFlow project on the Pro plan or higher
  • Firebase project with Firestore and Cloud Functions enabled
  • A Stripe account for coin pack purchases (optional for free-only apps)
  • Lottie animations for coin effects (free from lottiefiles.com)

Step-by-step guide

1

Design the Firestore schema for wallet and transactions

Add a coinBalance (int) field to your users collection, initialized to 0 on signup. Add a dailyBonusStreak (int) and lastBonusClaim (Timestamp) field for the daily bonus system. Create a subcollection `users/{uid}/transactions` with fields: type (String — earned, spent, purchased, bonus, referral), amount (int — positive for credits, negative for debits), description (String), balanceBefore (int), balanceAfter (int), and timestamp (Timestamp). Create a `coin_packs` collection with documents for each purchasable pack: name (String), coinAmount (int), priceUsd (double), stripePriceId (String), and iconUrl (String).

Expected result: The schema supports balance tracking, a complete transaction audit trail, and configurable coin packs for purchase.

2

Build the wallet card UI with animated balance display

Create a WalletPage with a prominent wallet card Container at the top. Style it with a gradient background (gold to dark amber) and rounded corners. Inside, place a Row with a coin Image asset on the left and a Column on the right showing 'Your Coins' label and the balance amount as a large bold Text bound to currentUserDocument.coinBalance. Below the balance, add a Row of quick-action Buttons: 'Buy Coins', 'Daily Bonus', and 'Transaction History'. Add a LottieAnimation widget positioned behind the balance text that plays a coin shimmer animation on page load for visual polish.

Expected result: The wallet page shows a visually appealing card with the coin balance, a shimmer animation, and quick-action buttons.

3

Create the coin purchase flow with Stripe and Cloud Function

Below the wallet card, add a 'Buy Coins' section with a GridView bound to a Backend Query on the coin_packs collection. Each pack shows a Container with the coin amount, price, and a Buy button. On Buy tap, call a Cloud Function named purchaseCoinPack that creates a Stripe Checkout Session in payment mode using the pack's stripePriceId and the user's ID as client_reference_id. Return the session URL and launch it. Create a Stripe webhook Cloud Function that listens for checkout.session.completed events. On success, read the purchased pack's coinAmount, use a Firestore transaction to atomically read the current balance, add the coins, write the new balance, and create a transaction document with type 'purchased'.

purchaseWebhook.js
1// Cloud Function: purchaseCoinPack webhook handler
2const event = stripe.webhooks.constructEvent(
3 req.rawBody, sig, secret
4);
5
6if (event.type === 'checkout.session.completed') {
7 const session = event.data.object;
8 const userId = session.client_reference_id;
9 const packId = session.metadata.packId;
10
11 const packDoc = await db.doc(`coin_packs/${packId}`).get();
12 const coinAmount = packDoc.data().coinAmount;
13
14 await db.runTransaction(async (tx) => {
15 const userRef = db.doc(`users/${userId}`);
16 const user = await tx.get(userRef);
17 const before = user.data().coinBalance || 0;
18 const after = before + coinAmount;
19
20 tx.update(userRef, { coinBalance: after });
21 tx.create(
22 userRef.collection('transactions').doc(), {
23 type: 'purchased',
24 amount: coinAmount,
25 description: `Purchased ${coinAmount} coins`,
26 balanceBefore: before,
27 balanceAfter: after,
28 timestamp: admin.firestore.FieldValue
29 .serverTimestamp(),
30 }
31 );
32 });
33}

Expected result: Users can buy coin packs via Stripe. On successful payment, coins are added atomically to their balance with a transaction record.

4

Implement the daily bonus with streak multiplier

Add a 'Claim Daily Bonus' button on the wallet page. On tap, call a Cloud Function named claimDailyBonus. The function checks the user's lastBonusClaim timestamp. If it was less than 24 hours ago, reject with 'Already claimed today'. If it was between 24-48 hours ago, increment the streak. If more than 48 hours, reset the streak to 1. Calculate the bonus amount: base 10 coins multiplied by the streak (capped at 7x). Use a Firestore transaction to update coinBalance, dailyBonusStreak, lastBonusClaim, and create a transaction document with type 'bonus'. In FlutterFlow, on successful claim, play the Lottie coin animation and show a SnackBar with 'Day {streak}: You earned {amount} coins!'.

Expected result: Users claim a daily coin bonus that grows with consecutive days. The streak resets if they miss a day, encouraging daily app usage.

5

Build the spend flow for the in-app store

Create an in-app Store page with items that cost coins. Each item has a coinPrice field. On the Buy with Coins button tap, call a Cloud Function named spendCoins that accepts the userId and coinPrice. The function validates that coinBalance >= coinPrice using a Firestore transaction. If sufficient, deduct the coins, create a transaction document with type 'spent', and return success. If insufficient, return an error with 'Not enough coins — you need {shortage} more'. In FlutterFlow, on success, show a success animation and update the UI. On failure, show an alert dialog with the error message and a 'Buy More Coins' button linking to the purchase section.

Expected result: Users can spend coins on in-app items. Insufficient balance shows a clear error with an option to purchase more coins.

6

Display the transaction history feed

Create a Transaction History section accessible via the wallet card quick-action button or a separate page. Add a Backend Query on `users/{uid}/transactions` ordered by timestamp descending. Bind results to a ListView. Each item shows a Container with a left icon colored by type (green coin for earned/purchased/bonus, red minus for spent), the description text, the amount (positive amounts with a + prefix in green, negative in red), and the relative timestamp. Add ChoiceChips above the list to filter by transaction type: All, Earned, Spent, Purchased, Bonus. Set Single Time Query to OFF so new transactions appear in real time.

Expected result: Users see a complete, filterable history of all coin transactions with clear visual indicators for credits and debits.

Complete working example

Cloud Function: claimDailyBonus
1// Cloud Function: claimDailyBonus
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4admin.initializeApp();
5
6const db = admin.firestore();
7
8exports.claimDailyBonus = functions.https
9 .onCall(async (data, context) => {
10 if (!context.auth) throw new functions.https
11 .HttpsError('unauthenticated', 'Login required');
12
13 const userId = context.auth.uid;
14 const userRef = db.doc(`users/${userId}`);
15
16 return db.runTransaction(async (tx) => {
17 const user = await tx.get(userRef);
18 const userData = user.data();
19 const balance = userData.coinBalance || 0;
20 const lastClaim = userData.lastBonusClaim?.toDate();
21 const streak = userData.dailyBonusStreak || 0;
22 const now = new Date();
23
24 // Check if already claimed today
25 if (lastClaim) {
26 const hoursSince =
27 (now - lastClaim) / (1000 * 60 * 60);
28 if (hoursSince < 24) {
29 throw new functions.https.HttpsError(
30 'failed-precondition',
31 'Already claimed today'
32 );
33 }
34 }
35
36 // Calculate streak
37 let newStreak = 1;
38 if (lastClaim) {
39 const hoursSince =
40 (now - lastClaim) / (1000 * 60 * 60);
41 if (hoursSince <= 48) {
42 newStreak = Math.min(streak + 1, 7);
43 }
44 }
45
46 // Calculate bonus: base 10 * streak multiplier
47 const bonusAmount = 10 * newStreak;
48 const newBalance = balance + bonusAmount;
49
50 tx.update(userRef, {
51 coinBalance: newBalance,
52 dailyBonusStreak: newStreak,
53 lastBonusClaim:
54 admin.firestore.FieldValue.serverTimestamp(),
55 });
56
57 tx.create(
58 userRef.collection('transactions').doc(),
59 {
60 type: 'bonus',
61 amount: bonusAmount,
62 description:
63 `Day ${newStreak} bonus: ${bonusAmount} coins`,
64 balanceBefore: balance,
65 balanceAfter: newBalance,
66 timestamp:
67 admin.firestore.FieldValue.serverTimestamp(),
68 }
69 );
70
71 return {
72 streak: newStreak,
73 amount: bonusAmount,
74 newBalance: newBalance,
75 };
76 });
77 });

Common mistakes

Why it's a problem: Allowing clients to directly update the coinBalance field without server validation

How to avoid: All balance modifications must go through Cloud Functions that validate the operation. Firestore Security Rules should deny direct writes to the coinBalance field from clients.

Why it's a problem: Allowing the spend action without checking balance first

How to avoid: Always verify coinBalance >= spendAmount inside a Firestore transaction in the Cloud Function BEFORE deducting. Return an 'Insufficient coins' error if the check fails.

Why it's a problem: Not using Firestore transactions for balance updates

How to avoid: Wrap every balance modification in a Firestore transaction that atomically reads the current balance, calculates the new balance, and writes both the update and the transaction record.

Best practices

  • Record every balance change as a transaction document with balanceBefore and balanceAfter for full auditability
  • Cap the daily bonus streak multiplier at 7x to prevent runaway inflation of the in-app economy
  • Use Lottie animations for coin earn events to create a satisfying, game-like experience
  • Show the coin balance in the app header or navigation bar so users always know their current amount
  • Offer multiple coin pack sizes with the best value on larger packs to encourage bigger purchases
  • Set Firestore Security Rules to deny direct client writes to coinBalance — only Cloud Functions should modify it
  • Add a 'Not enough coins' state on store items that shows how many more coins the user needs

Still stuck?

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

ChatGPT Prompt

I'm building an in-app virtual currency wallet in FlutterFlow. I need Firestore schema for coin balance and transactions, Cloud Functions for purchasing coins via Stripe, a daily bonus with streak multiplier, and a spend flow with balance validation. Show me the complete architecture and code.

FlutterFlow Prompt

Create a wallet page with a gold gradient card showing coin balance and quick actions. Below it, add a grid of coin purchase packs with Buy buttons. Add a Daily Bonus button that rewards coins with a streak multiplier. Include a transaction history list showing all earn, spend, and purchase events.

Frequently asked questions

How do I prevent users from claiming the daily bonus multiple times?

The Cloud Function checks the lastBonusClaim timestamp. If less than 24 hours have passed since the last claim, it rejects the request with an 'Already claimed today' error. This is enforced server-side so it cannot be bypassed.

Can users transfer coins to other users?

Yes. Create a transferCoins Cloud Function that accepts senderId, recipientId, and amount. Use a Firestore transaction to deduct from the sender and credit the recipient atomically. Create transaction records for both users.

How do I handle coin refunds for failed purchases?

Create a refundCoins Cloud Function that takes the original transaction ID. Verify the original transaction exists and was a spend type. Add the coins back to the balance and create a transaction with type 'refund'.

What happens to the streak if the user claims their bonus at 11 PM and again at 1 AM?

The Cloud Function checks hours since last claim, not calendar days. Claims less than 24 hours apart are rejected. To use calendar days instead, compare the date portions of the timestamps.

Can I use in-app purchases instead of Stripe for coin packs?

Yes. Use Flutter's in_app_purchase package as a Custom Action. The purchase verification should go through a Cloud Function that validates the receipt with Apple/Google before crediting coins.

Can RapidDev help build a complete in-app economy system?

Yes. RapidDev can implement sophisticated virtual economies with multiple currency types, exchange markets, gifting, auctions, anti-inflation mechanisms, and analytics dashboards.

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.