Gamifying Trust: Building a 6-Level Reputation System for P2P Marketplaces
If you are building a peer-to-peer marketplace, you are really building a trust engine. The core question is not "Can we list items?" It is "Will strangers feel safe renting from each other?" On RentFox, we needed a system that makes trust visible, measurable, and hard to fake.
That led us to a six-level reputation model that turns good behavior into progress: New User -> Bronze -> Silver -> Gold -> Platinum -> Diamond. This article explains how the scoring model works, how we store and compute it in Node.js + MongoDB, and how we designed the UX so it feels fair and motivating.
This is part 5 of our Building RentFox series. If you missed earlier posts, we covered architecture, AI disputes, Flutter services, and MongoDB geospatial search. This time, it is product design and backend mechanics working together.
Why Trust Scores Matter in P2P
Marketplaces fail when trust is invisible. A rating alone does not answer key questions:
- Is this user verified?
- Do they show up on time?
- Do they return items undamaged?
- Do they resolve disputes quickly?
We wanted a single score that answers: "Is this person a good rental partner?" That score needs to:
- Reward consistent behavior (not just one good review).
- Encourage verification and completeness.
- Penalize risky behavior without being overly punitive.
- Be transparent enough to feel fair.
- Be hard to game.
So we built a trust score that is multi-factor, event-driven, and level-based.
The 6 Levels (And Why Levels Beat Raw Scores)
A raw score like 742 is hard to interpret. A level like "Gold" is instant. We use levels as the primary UI signal and show the numeric score only in the profile details.
Level thresholds:
- New User: 0-99
- Bronze: 100-249
- Silver: 250-449
- Gold: 450-649
- Platinum: 650-849
- Diamond: 850+
This lets us set clear goals and build progress UI ("92 points to Silver"). It also gives us a place to attach perks: faster payouts, higher listing limits, or reduced deposits.
The Trust Score Formula
We wanted the score to balance verifications, reviews, and behavioral signals. Here is the model we settled on:
Total Score = Verifications + Reviews + Activity + Behavior - Penalties
We cap each category to prevent a single dimension from dominating.
1) Verifications (Max 250 points)
These signals are hard to fake and build baseline trust:
- Phone verified: +50
- Email verified: +25
- Government ID verified: +100
- Payment method verified: +50
- Address verified: +25
Why this matters: New users can get to Bronze quickly by verifying, which reduces cold-start risk.
2) Reviews (Max 200 points)
Reviews should matter, but we do not want a single 5-star review to create false confidence.
We use a weighted average plus volume bonus:
- Average rating (1-5) scaled to 0-150
- Review count bonus capped at +50
3) Activity (Max 300 points)
This rewards real usage and consistency:
- Completed rentals as lender: +10 each
- Completed rentals as renter: +8 each
- Repeat rentals with same partner: +5 each (trust loop)
- On-time pickup/return streaks: +2 each
We cap the total so high-volume users do not completely dominate the leaderboard.
4) Behavior (Max 150 points)
This captures good marketplace behavior beyond rentals:
- Responds to messages within 1 hour: +2
- Keeps availability calendar updated: +1 per week
- Uses evidence photos consistently: +3 per rental
These are small signals, but they add up and reinforce healthy habits.
5) Penalties (No hard cap)
Negative events reduce trust quickly:
- Late return: -15
- Damaged item confirmed: -50
- Dispute resolved against user: -30
- Chargeback: -100
- Fraud flag: -250
Penalties are designed to be stronger than a single positive action, but not so strong that recovery feels impossible.
Data Model: Trust Ledger, Not Just a Score
A common mistake is storing a single trustScore field and updating it directly. That makes debugging impossible. We store events in a ledger, then compute the score from those events.
This gives us:
- Auditability (why did a user drop from Gold to Silver?)
- Flexibility (recalculate scores when weights change)
- A clear trail for dispute reviews
Trust Event Schema (MongoDB)
// models/TrustEvent.js
const mongoose = require('mongoose');
const trustEventSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', index: true },
type: { type: String, required: true },
points: { type: Number, required: true },
metadata: {
sourceId: { type: String }, // bookingId, reviewId, etc.
note: { type: String }
},
createdAt: { type: Date, default: Date.now }
});
module.exports = mongoose.model('TrustEvent', trustEventSchema);
Trust Summary on User Profile
// models/User.js (excerpt)
const userSchema = new mongoose.Schema({
// ... user fields
trust: {
score: { type: Number, default: 0 },
level: { type: String, default: 'New User' },
lastCalculatedAt: { type: Date }
}
});
We store the final score on the user for fast reads, but the ledger is the source of truth.
Event-Driven Updates: How Scores Change
Every time something trust-related happens, we create a TrustEvent. Then a recalculation job updates the user score. We do this in two steps because scoring can be expensive when a user has thousands of events.
1) Create events as things happen
// services/trustService.js
const TrustEvent = require('../models/TrustEvent');
const TRUST_POINTS = {
PHONE_VERIFIED: 50,
EMAIL_VERIFIED: 25,
ID_VERIFIED: 100,
PAYMENT_VERIFIED: 50,
ADDRESS_VERIFIED: 25,
RENTAL_COMPLETED_LENDER: 10,
RENTAL_COMPLETED_RENTER: 8,
LATE_RETURN: -15,
DISPUTE_LOST: -30
};
async function addTrustEvent(userId, type, metadata = {}) {
const points = TRUST_POINTS[type] || 0;
// Always store the event, even if points = 0
await TrustEvent.create({
userId,
type,
points,
metadata
});
}
module.exports = { addTrustEvent };
2) Recalculate trust score (daily or on-demand)
// jobs/recalculateTrustScores.js
const TrustEvent = require('../models/TrustEvent');
const User = require('../models/User');
const LEVELS = [
{ name: 'New User', min: 0 },
{ name: 'Bronze', min: 100 },
{ name: 'Silver', min: 250 },
{ name: 'Gold', min: 450 },
{ name: 'Platinum', min: 650 },
{ name: 'Diamond', min: 850 }
];
function getLevel(score) {
return LEVELS.slice().reverse().find(level => score >= level.min).name;
}
async function recalculateUserTrust(userId) {
const events = await TrustEvent.find({ userId });
const score = events.reduce((sum, evt) => sum + evt.points, 0);
const level = getLevel(score);
await User.updateOne(
{ _id: userId },
{
$set: {
'trust.score': score,
'trust.level': level,
'trust.lastCalculatedAt': new Date()
}
}
);
}
module.exports = { recalculateUserTrust };
Why this approach: We can batch recalculations nightly, and still trigger on-demand recalculation for specific users after disputes.
Preventing Score Gaming
Any gamified system invites manipulation. We added guardrails:
1) Diminishing returns
- First 5 rentals count full points
- Rentals 6-20 are worth 50%
- After 20, no additional points from volume
2) Trust decay
Inactive users slowly lose activity points. This prevents old high scores from dominating:
// Example decay: remove 2 points per inactive week
const INACTIVITY_PENALTY = 2;
3) Review quality checks
We ignore reviews from suspicious patterns:
- Same lender/renter pair too frequently
- Reviews submitted from same IP within minutes
- Abnormally high rating spikes
4) Manual override
Admins can flag or adjust trust scores with full audit logging. This is critical for edge cases and fraud response.
Making It Feel Fair: UX and UI
Users will only trust a trust score if it feels transparent and achievable. Our UI focuses on clarity:
- Show current level + progress bar
- List top 3 things that would increase their score
- Explain penalties with short text ("Late return: -15")
Example of the profile display:
Trust Level: Silver (312)
Progress to Gold: 138 points
Top ways to level up:
- Verify your ID (+100)
- Complete 3 rentals (+30)
- Keep calendar updated for 4 weeks (+4)
We avoid showing raw formulas on the main UI, but we provide a "How scoring works" info page for transparency.
Results and Lessons Learned
We have not fully launched yet, but in testing the system gave us a few insights:
- Verifications drive early adoption. Users reach Bronze quickly, which reduces anxiety for first rentals.
- Levels beat numbers. People understand "Gold" instantly, but ignore raw scores.
- Penalties must be recoverable. We tuned penalties so users can recover with consistent good behavior.
- Behavioral signals matter. Even small points for responsiveness improved response times in our beta.
The biggest lesson: your trust system is as much product design as it is backend logic. If it feels unfair, it will backfire.
Join the RentFox Waitlist
We are launching RentFox in early 2026, and the waitlist is live. If you want to see the trust system in action (and help shape it), join us:
Join the waitlist at rentfox.revolvo.tech
It takes 30 seconds, and you will get early access when we launch in your city.
What's Next
In the final article of this series, we will break down our Stripe escrow flow: authorize at booking, capture at pickup, and release after return. If you are building marketplace payments, this will be the most practical guide in the series.
Conclusion
Trust is the foundation of every peer-to-peer marketplace. A good trust system makes it visible, measurable, and motivating without being easy to manipulate.
Our six-level model gave RentFox a clear, user-friendly way to reward good behavior and reduce risk. The ledger-based approach in MongoDB keeps the system auditable, while the Node.js scoring job keeps it fast and scalable.
If you are building a marketplace and want help designing systems like this, reach out to Revolvo Tech. We love working on trust, safety, and marketplace infrastructure.
Questions or feedback? Drop a comment and let us know what you would change.
Top comments (0)