Build a digital wallet feature in Bubble by adding a balance field to the User data type, creating a Transaction data type for history, and integrating Stripe for top-ups. This tutorial covers the full wallet lifecycle — adding funds, spending credits, displaying balance, and maintaining a transaction ledger.
Overview: Digital Wallet in Bubble
A digital wallet lets users store credits or funds inside your app, spend them on services, and view their transaction history. This tutorial builds a wallet system using Bubble's database for balance tracking and Stripe for real-money top-ups. It is designed for non-technical founders building marketplaces, SaaS apps, or platforms that need an internal currency.
Prerequisites
- A Bubble account with user authentication set up
- A Stripe account (test mode is fine for development)
- The Stripe plugin installed in Bubble
- Basic understanding of Data Types and Workflows
Step-by-step guide
Add wallet fields to the User data type
Add wallet fields to the User data type
Go to Data tab → Data types → User. Add a new field called 'wallet_balance' of type number (default value: 0). This field stores the user's current credit balance. Optionally add a 'wallet_currency' text field if you support multiple currencies.
Pro tip: Store amounts in the smallest unit (cents) to avoid floating-point issues. Display as dollars by dividing by 100.
Expected result: The User data type has a wallet_balance field set to 0 for new users.
Create the Transaction data type
Create the Transaction data type
Create a new Data Type called 'Transaction' with fields: user (User), amount (number — positive for credits, negative for debits), type (Option Set: top_up, purchase, refund, transfer), description (text), balance_after (number — the wallet balance after this transaction), and stripe_charge_id (text — for linking to Stripe payments). This provides a complete audit trail of every wallet change.
Expected result: A Transaction data type exists with fields for amount, type, description, and balance tracking.
Build the wallet dashboard page
Build the wallet dashboard page
Create a page called 'wallet.' At the top, add a Text element displaying 'Balance: $' followed by Current User's wallet_balance / 100 :formatted as currency. Below, add a Button labeled 'Add Funds' and a Repeating Group with data source: Do a search for Transaction (constraint: user = Current User), sorted by Created Date descending. In each cell, display the date, type, description, amount (formatted with +/- sign), and balance_after.
Expected result: Users see their current balance and a scrollable list of all past transactions.
Set up Stripe Checkout for adding funds
Set up Stripe Checkout for adding funds
On the 'Add Funds' button, create a workflow. Add preset amount options (like $10, $25, $50) using a set of buttons or a dropdown. When the user clicks 'Add Funds' with a selected amount, the workflow action is: Charge the current user (Stripe plugin action) → Amount = selected amount in cents, Currency = usd, Description = 'Wallet top-up.' On success, add a second action: Make changes to Current User → wallet_balance = Current User's wallet_balance + amount. Then: Create a new Transaction → user = Current User, amount = the top-up amount, type = top_up, description = 'Added funds via Stripe', balance_after = Current User's wallet_balance.
Expected result: Users can add real money to their wallet via Stripe, and the balance and transaction history update immediately.
Create a workflow for spending wallet credits
Create a workflow for spending wallet credits
When a user makes a purchase in your app, add wallet deduction logic to the purchase workflow. First, check if Current User's wallet_balance >= purchase amount. If yes: Make changes to Current User → wallet_balance = Current User's wallet_balance - amount. Then Create a new Transaction → amount = negative amount, type = purchase, description = item name, balance_after = Current User's wallet_balance. If insufficient balance, show an alert: 'Insufficient wallet balance. Please add funds.'
Pro tip: Use a backend workflow for the deduction to prevent race conditions where two simultaneous purchases could overdraw the balance.
Expected result: Purchases deduct from the wallet balance and create a transaction record. Insufficient funds are handled gracefully.
Add privacy rules to protect wallet data
Add privacy rules to protect wallet data
Go to Data tab → Privacy. On Transaction: add a rule 'When This Transaction's user is Current User' → allow Find in searches and View all fields. This ensures users can only see their own transactions. On the User type, ensure wallet_balance is not exposed to other users by restricting field-level visibility to the user themselves or admins.
Expected result: Users can only view their own wallet balance and transaction history. Other users cannot access this data.
Complete working example
1DIGITAL WALLET — WORKFLOW SUMMARY2==================================34DATA MODEL:5 User (modified):6 + wallet_balance (number, default: 0, stored in cents)7 + wallet_currency (text, default: "usd")89 Transaction (new):10 - user (User)11 - amount (number — positive=credit, negative=debit)12 - type (Option Set: top_up, purchase, refund, transfer)13 - description (text)14 - balance_after (number)15 - stripe_charge_id (text)1617WORKFLOW: Add Funds18 Event: When "Add Funds" button is clicked19 Condition: Dropdown amount is not empty20 Action 1: Charge current user (Stripe)21 Amount: Dropdown's value × 100 (convert to cents)22 Currency: usd23 Action 2: Make changes to Current User24 wallet_balance = wallet_balance + charge amount25 Action 3: Create Transaction26 user = Current User27 amount = charge amount28 type = top_up29 description = "Added funds via Stripe"30 balance_after = Current User's wallet_balance3132WORKFLOW: Spend Credits33 Event: When "Purchase" button is clicked34 Condition: Current User's wallet_balance >= item price35 Action 1: Make changes to Current User36 wallet_balance = wallet_balance - item price37 Action 2: Create Transaction38 amount = -(item price)39 type = purchase40 description = item name41 balance_after = Current User's wallet_balance42 ELSE (insufficient balance):43 Show alert: "Insufficient wallet balance"4445PRIVACY:46 Transaction: user = Current User → Find + View47 User wallet_balance: visible only to self + adminCommon mistakes when setting up a digital wallet in Bubble.io: Step-by-Step Guide
Why it's a problem: Using frontend workflows for balance deductions without backend validation
How to avoid: Use a backend workflow with a balance check for all deductions to prevent race conditions
Why it's a problem: Storing currency amounts as decimals instead of cents
How to avoid: Store all amounts in cents (integers) and divide by 100 only for display purposes
Why it's a problem: Not recording the balance_after on each transaction
How to avoid: Always store the resulting balance on each Transaction record for a complete audit trail
Best practices
- Store all monetary values in cents to avoid floating-point rounding issues
- Use backend workflows for balance changes to prevent simultaneous deduction race conditions
- Record every balance change as a Transaction for a complete audit trail
- Add privacy rules so users can only view their own wallet and transactions
- Include a balance_after field on every transaction for easy reconciliation
- Implement a minimum top-up amount to reduce Stripe transaction fees per top-up
- Add admin tools to credit or debit user wallets manually for refunds and adjustments
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
I want to build a digital wallet system in my Bubble.io app where users can add funds via Stripe, spend credits on services, and view their transaction history. Can you design the data model and outline the key workflows for top-ups and purchases?
Build a digital wallet feature for my app. Add a wallet_balance field to the User type, create a Transaction data type, and set up workflows for adding funds via Stripe and spending credits on purchases. Create a wallet dashboard page showing balance and transaction history.
Frequently asked questions
Can I build the wallet without Stripe?
Yes, for a virtual currency system that does not involve real money. Skip the Stripe integration and add credits manually via admin workflows or as rewards for actions.
How do I handle refunds to the wallet?
Create a refund workflow that adds the amount back to wallet_balance and creates a Transaction with type = refund. If the original payment was via Stripe, also process a Stripe refund.
Is storing wallet balance on the User record secure?
It is secure if you add privacy rules that prevent other users from viewing or modifying the wallet_balance field, and use backend workflows for all balance changes.
Can users transfer credits to other users?
Yes. Create a transfer workflow that deducts from the sender's balance and adds to the recipient's balance, creating two Transaction records — one debit and one credit — both with type = transfer.
What happens if a Stripe charge succeeds but the balance update fails?
Use Stripe webhooks to confirm successful charges. Set up a backend workflow triggered by the checkout.session.completed webhook that updates the balance, ensuring the balance only changes when payment is truly confirmed.
Can RapidDev help build a payment and wallet system?
Yes. RapidDev has experience building complex wallet and payment systems in Bubble including multi-currency support, automated reconciliation, and fraud prevention.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation