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

How to Create a User Reward System with Custom Rules in FlutterFlow

Build a configurable points engine using a reward_rules collection defining actions (purchase, review, referral, daily_login) with point values and per-day limits, a rewardPoints field on user documents, and a point_transactions log. Cloud Functions listen for Firestore events and award points based on matching rules. Users spend points in a rewards_catalog by redeeming items through an atomic transaction that deducts points and creates a redemption record. A daily login check awards bonus points once per day.

What you'll learn

  • How to model configurable reward rules with actions, points, and daily limits
  • How to award points securely through Cloud Functions triggered by Firestore events
  • How to build a rewards catalog where users redeem points for items
  • How to implement a daily login bonus with cooldown enforcement
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)March 2026RapidDev Engineering Team
TL;DR

Build a configurable points engine using a reward_rules collection defining actions (purchase, review, referral, daily_login) with point values and per-day limits, a rewardPoints field on user documents, and a point_transactions log. Cloud Functions listen for Firestore events and award points based on matching rules. Users spend points in a rewards_catalog by redeeming items through an atomic transaction that deducts points and creates a redemption record. A daily login check awards bonus points once per day.

Building a Configurable Points Reward System in FlutterFlow

A reward system drives engagement by giving users points for actions like purchases, reviews, and daily logins. This tutorial builds a fully configurable engine where admins define rules in Firestore, Cloud Functions enforce point awards securely, users browse a redemption catalog, and the daily login bonus encourages daily return visits. It is designed for any app that wants to incentivize user behavior.

Prerequisites

  • A FlutterFlow project on the Pro plan with Cloud Functions
  • Firebase project with Firestore and Authentication enabled
  • Basic understanding of Cloud Functions and Firestore triggers
  • Familiarity with FlutterFlow App State and Backend Queries

Step-by-step guide

1

Create the reward rules and points schema

Create a reward_rules collection with fields: action (String: 'purchase', 'review', 'referral', 'daily_login'), pointsAwarded (Integer), maxPerDay (Integer, -1 for unlimited), isActive (Boolean). Add a rewardPoints field (Integer, default 0) to the users collection. Create a point_transactions collection with: userId (String), action (String), points (Integer), timestamp (Timestamp), and reference (String, the related document ID like orderId). Create a rewards_catalog collection with: name (String), description (String), imageUrl (String), pointsCost (Integer), stock (Integer), and isAvailable (Boolean).

Expected result: Firestore has reward_rules for configuring point values, point_transactions for logging, and rewards_catalog for redemption items.

2

Build Cloud Functions that award points on Firestore events

Create a Cloud Function called awardPoints that triggers on Firestore document creation events. For example, when a new order document is created, the function reads the reward_rules document for 'purchase', checks if the rule is active, queries point_transactions for the user's awards today for that action against maxPerDay, and if within limits, increments the user's rewardPoints using FieldValue.increment and creates a point_transaction log entry. Create similar triggers for review creation and referral events. Each trigger follows the same pattern: read rule, check cooldown, award points, log transaction.

awardPurchasePoints.js
1// Cloud Function: awardPurchasePoints
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4admin.initializeApp();
5
6exports.awardPurchasePoints = functions.firestore
7 .document('orders/{orderId}')
8 .onCreate(async (snap, context) => {
9 const order = snap.data();
10 const db = admin.firestore();
11 const ruleSnap = await db.collection('reward_rules')
12 .where('action', '==', 'purchase').where('isActive', '==', true).limit(1).get();
13 if (ruleSnap.empty) return;
14 const rule = ruleSnap.docs[0].data();
15
16 if (rule.maxPerDay > 0) {
17 const todayStart = new Date(); todayStart.setHours(0,0,0,0);
18 const todayAwards = await db.collection('point_transactions')
19 .where('userId', '==', order.userId)
20 .where('action', '==', 'purchase')
21 .where('timestamp', '>=', admin.firestore.Timestamp.fromDate(todayStart))
22 .get();
23 if (todayAwards.size >= rule.maxPerDay) return;
24 }
25
26 await db.collection('users').doc(order.userId)
27 .update({ rewardPoints: admin.firestore.FieldValue.increment(rule.pointsAwarded) });
28 await db.collection('point_transactions').add({
29 userId: order.userId, action: 'purchase',
30 points: rule.pointsAwarded, reference: context.params.orderId,
31 timestamp: admin.firestore.FieldValue.serverTimestamp(),
32 });
33 });

Expected result: When a new order is created, the Cloud Function checks the purchase rule, enforces daily limits, awards points, and logs the transaction.

3

Implement the daily login bonus

Add a lastLoginRewardDate (Timestamp) field to the users collection. On the home page On Page Load action, create a Custom Action or Cloud Function that checks if lastLoginRewardDate is today. If not, read the daily_login reward rule, award the points by incrementing rewardPoints and creating a point_transaction, and update lastLoginRewardDate to today. Show a celebratory SnackBar or dialog: 'Daily bonus! +{points} points'. If lastLoginRewardDate is already today, skip the award silently. This encourages users to open the app daily.

Expected result: Users receive bonus points once per day on first app open. A celebratory message confirms the award. Subsequent opens on the same day skip the bonus.

4

Build the points dashboard and transaction history

Create a RewardsDashboard page. At the top, display the user's current rewardPoints in a large headlineLarge Text widget with a coin or star Icon. Below, add a Row of summary cards showing: points earned this week, points earned this month, and total points redeemed (query point_transactions with date filters and aggregate). Add a ListView of recent point_transactions ordered by timestamp descending, each showing the action icon, description, points amount (green for earned, red for redeemed), and timestamp. Use Conditional Styling to color positive transactions green and negative (redemptions) red.

Expected result: The dashboard shows the current points balance, weekly/monthly summaries, and a chronological transaction history with color-coded entries.

5

Create the rewards catalog with redemption flow

Create a RewardsCatalog page with a GridView of rewards_catalog items showing image, name, points cost, and a Redeem button. The Redeem button is disabled (greyed out with Conditional Styling) when the user's rewardPoints are less than the item's pointsCost or stock is 0. On Redeem tap, show a confirmation dialog. On confirm, call a Cloud Function called redeemReward that runs a Firestore transaction: read user's rewardPoints, verify sufficient balance, decrement rewardPoints by pointsCost, decrement the reward's stock, and create a redemption record in a redemptions collection (userId, rewardId, rewardName, pointsSpent, redeemedAt).

redeemReward.js
1// Cloud Function: redeemReward
2exports.redeemReward = functions.https.onCall(async (data, context) => {
3 if (!context.auth) throw new functions.https.HttpsError('unauthenticated', 'Login required');
4 const { rewardId } = data;
5 const uid = context.auth.uid;
6 const db = admin.firestore();
7 const userRef = db.collection('users').doc(uid);
8 const rewardRef = db.collection('rewards_catalog').doc(rewardId);
9
10 return db.runTransaction(async (tx) => {
11 const userDoc = await tx.get(userRef);
12 const rewardDoc = await tx.get(rewardRef);
13 if (!rewardDoc.exists) throw new functions.https.HttpsError('not-found', 'Reward not found');
14 const reward = rewardDoc.data();
15 const userPoints = userDoc.data().rewardPoints || 0;
16 if (userPoints < reward.pointsCost) {
17 throw new functions.https.HttpsError('failed-precondition', 'Not enough points');
18 }
19 if (reward.stock <= 0) {
20 throw new functions.https.HttpsError('failed-precondition', 'Out of stock');
21 }
22 tx.update(userRef, { rewardPoints: admin.firestore.FieldValue.increment(-reward.pointsCost) });
23 tx.update(rewardRef, { stock: admin.firestore.FieldValue.increment(-1) });
24 tx.create(db.collection('redemptions').doc(), {
25 userId: uid, rewardId, rewardName: reward.name,
26 pointsSpent: reward.pointsCost,
27 redeemedAt: admin.firestore.FieldValue.serverTimestamp(),
28 });
29 tx.create(db.collection('point_transactions').doc(), {
30 userId: uid, action: 'redemption', points: -reward.pointsCost,
31 reference: rewardId, timestamp: admin.firestore.FieldValue.serverTimestamp(),
32 });
33 return { success: true };
34 });
35});

Expected result: Users browse available rewards, tap Redeem on affordable items, and points are deducted atomically. The transaction logs the redemption.

6

Build the admin rules management page

Create an AdminRewards page accessible only to admin users. Display a ListView of reward_rules showing the action name, points awarded, daily limit, and active status toggle. Each rule has an Edit button that opens a dialog to change pointsAwarded and maxPerDay. The isActive Switch allows admins to enable or disable rules without deleting them. Below the rules list, add a section for managing the rewards_catalog with Add, Edit, and Delete actions. This lets admins adjust the reward economy without deploying code changes.

Expected result: Admins can view, toggle, and edit reward rules and catalog items from within the app. Changes take effect immediately for all users.

Complete working example

reward_system_cloud_functions.js
1// Cloud Functions: Reward System — Award + Redeem
2const functions = require('firebase-functions');
3const admin = require('firebase-admin');
4admin.initializeApp();
5
6// Generic point award helper
7async function awardPointsForAction(userId, action, reference) {
8 const db = admin.firestore();
9 const ruleSnap = await db.collection('reward_rules')
10 .where('action', '==', action)
11 .where('isActive', '==', true).limit(1).get();
12 if (ruleSnap.empty) return null;
13 const rule = ruleSnap.docs[0].data();
14
15 if (rule.maxPerDay > 0) {
16 const todayStart = new Date();
17 todayStart.setHours(0, 0, 0, 0);
18 const todayAwards = await db.collection('point_transactions')
19 .where('userId', '==', userId)
20 .where('action', '==', action)
21 .where('timestamp', '>=', admin.firestore.Timestamp.fromDate(todayStart))
22 .get();
23 if (todayAwards.size >= rule.maxPerDay) return null;
24 }
25
26 await db.collection('users').doc(userId).update({
27 rewardPoints: admin.firestore.FieldValue.increment(rule.pointsAwarded),
28 });
29 await db.collection('point_transactions').add({
30 userId, action, points: rule.pointsAwarded,
31 reference: reference || '',
32 timestamp: admin.firestore.FieldValue.serverTimestamp(),
33 });
34 return rule.pointsAwarded;
35}
36
37// Trigger: new order
38exports.awardPurchasePoints = functions.firestore
39 .document('orders/{orderId}')
40 .onCreate(async (snap, ctx) => {
41 await awardPointsForAction(snap.data().userId, 'purchase', ctx.params.orderId);
42 });
43
44// Trigger: new review
45exports.awardReviewPoints = functions.firestore
46 .document('reviews/{reviewId}')
47 .onCreate(async (snap, ctx) => {
48 await awardPointsForAction(snap.data().userId, 'review', ctx.params.reviewId);
49 });
50
51// Daily login (callable)
52exports.claimDailyLogin = functions.https.onCall(async (data, context) => {
53 if (!context.auth) throw new functions.https.HttpsError('unauthenticated', 'Login required');
54 const uid = context.auth.uid;
55 const result = await awardPointsForAction(uid, 'daily_login', 'daily');
56 if (result) {
57 await admin.firestore().collection('users').doc(uid).update({
58 lastLoginRewardDate: admin.firestore.FieldValue.serverTimestamp(),
59 });
60 }
61 return { awarded: result || 0 };
62});
63
64// Redeem reward
65exports.redeemReward = functions.https.onCall(async (data, context) => {
66 if (!context.auth) throw new functions.https.HttpsError('unauthenticated', 'Login required');
67 const { rewardId } = data;
68 const uid = context.auth.uid;
69 const db = admin.firestore();
70
71 return db.runTransaction(async (tx) => {
72 const userRef = db.collection('users').doc(uid);
73 const rewardRef = db.collection('rewards_catalog').doc(rewardId);
74 const [userDoc, rewardDoc] = await Promise.all([tx.get(userRef), tx.get(rewardRef)]);
75
76 if (!rewardDoc.exists) throw new functions.https.HttpsError('not-found', 'Reward not found');
77 const reward = rewardDoc.data();
78 if ((userDoc.data().rewardPoints || 0) < reward.pointsCost)
79 throw new functions.https.HttpsError('failed-precondition', 'Insufficient points');
80 if (reward.stock <= 0)
81 throw new functions.https.HttpsError('failed-precondition', 'Out of stock');
82
83 tx.update(userRef, { rewardPoints: admin.firestore.FieldValue.increment(-reward.pointsCost) });
84 tx.update(rewardRef, { stock: admin.firestore.FieldValue.increment(-1) });
85 tx.create(db.collection('redemptions').doc(), {
86 userId: uid, rewardId, rewardName: reward.name,
87 pointsSpent: reward.pointsCost,
88 redeemedAt: admin.firestore.FieldValue.serverTimestamp(),
89 });
90 return { success: true };
91 });
92});

Common mistakes when creating a User Reward System with Custom Rules in FlutterFlow

Why it's a problem: Awarding points on the client without Cloud Function validation

How to avoid: All point awards must go through Cloud Functions that validate the triggering event, check daily limits, and atomically update the balance.

Why it's a problem: Not enforcing daily limits on reward rules

How to avoid: Query point_transactions for the user and action within today's date range before awarding. Reject if count >= maxPerDay.

Why it's a problem: Deducting points for redemption on the client and creating the redemption separately

How to avoid: Use a Firestore transaction in a Cloud Function that atomically deducts points, decrements stock, and creates the redemption record.

Best practices

  • Store all reward rules in Firestore so admins can adjust point values without code changes
  • Log every point change in point_transactions for auditability and debugging
  • Use a generic helper function in Cloud Functions to reduce code duplication across triggers
  • Show the points balance prominently in the app header or navigation bar for constant visibility
  • Disable the Redeem button when points are insufficient rather than showing an error after tap
  • Add a leaderboard of top point earners to drive competitive engagement
  • Create seasonal or limited-time reward rules to boost engagement during promotions

Still stuck?

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

ChatGPT Prompt

I need to build a configurable points reward system in FlutterFlow. Show me the Firestore schema for reward rules with daily limits, Cloud Functions that trigger on Firestore events to award points, and a redemption Cloud Function with atomic point deduction and stock management.

FlutterFlow Prompt

Create a rewards dashboard page showing the user's point balance, recent point transactions in a ListView, and a rewards catalog GridView where users can redeem items. Disable the Redeem button when points are insufficient.

Frequently asked questions

Can I set different point values for different purchase amounts?

Yes. Modify the Cloud Function to read the order total and calculate points proportionally (e.g., 1 point per dollar spent) instead of a flat rate. Store the multiplier in the reward rule.

How do I implement reward tiers like Bronze, Silver, and Gold?

Add tier thresholds to a reward_tiers collection (e.g., Bronze: 0-500, Silver: 500-2000, Gold: 2000+). On the dashboard, compare the user's total points earned (lifetime) against thresholds to display their tier badge.

Can points expire after a certain period?

Yes. Add an expiresAt Timestamp to each point_transaction. Run a scheduled Cloud Function that deducts expired points by summing expired transactions and adjusting the user's rewardPoints balance.

How do I prevent users from gaming the system with fake reviews?

Only award review points for verified purchases. The Cloud Function should check that the reviewer has an order for the reviewed product before awarding points.

Can I offer physical rewards that require shipping?

Yes. Add a shippingRequired boolean and address fields to the redemption record. After redemption, create a fulfillment task in a fulfillment_orders collection for your team to process.

Can RapidDev help design a custom reward economy?

Yes. RapidDev can model your reward economy, implement the full points engine with anti-fraud measures, build admin dashboards for economy health monitoring, and integrate with third-party reward providers.

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.