Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
post
page
sponsor
Filter by Categories
Alternative Giving
Announcements
Business
Business Coaching
Charities We've Helped
Charity
Coding
Engineering
Guest Blog
How To
Marketing
Misc
PIFster Blog
Product Strategy
Search Engine Optimization (SEO)

Building a Gamified Referral System for Viral Giving

A stylized tree with glowing target-like circles on its branches, surrounded by flying arrows, celebrates the PIFster of the Month. A gold crown sits atop, highlighting a gamified referral engine amid decorative elements.
TL;DR: Most referral programs reward the referrer with discounts or cash — a transactional incentive that feels wrong in a nonprofit context. PIFster's gamified referral system rewards referrers with influence: the top referrer each month (and their entire referral tree) gets boosted voting power over which charity receives the community's pooled donations. This post explains the graph-based architecture, the vote multiplier system, and why a closure table made it all possible.

The Problem: Referral Incentives That Don't Fit Nonprofits

Referral programs are everywhere. Refer a friend, get $10 off. Get a free month. Earn points.

For a charitable giving platform, none of those work. You can't say "Refer a friend and we'll donate less of your money." The incentive has to be intrinsic — something that makes the referrer more effective at the thing they already care about.

Our answer: vote power multipliers. Refer people, and your vote in the monthly charity election counts for more.

How It Works (The 30-Second Version)

  1. Every PIFster member gets a unique 6-character referral code (e.g., K7NP3W)
  2. They share their link: pifster.org/join?ref=K7NP3W
  3. When someone signs up through that link, they become the referrer's "child" in the referral graph
  4. Each month, we rank referrers by new signups — the leader is crowned PIFster of the Month (POM)
  5. The POM and everyone in their referral tree (up to 3 levels deep) gets a vote multiplier
  6. That multiplier makes their vote count 2x, 3x, or more in the monthly charity election

The result: referring people doesn't just grow the community — it directly amplifies your influence over where the money goes. Aligned incentives.

The Gamified Referral Graph

This isn't a flat "who referred who" list. It's a directed graph with depth.

Alice (POM leader) ├── Bob (depth 1 — Alice referred Bob) │ ├── Carol (depth 2 — Bob referred Carol) │ │ └── Dave (depth 3 — Carol referred Dave) │ └── Eve (depth 2 — Bob referred Eve) └── Frank (depth 1 — Alice referred Frank)

If Alice is the POM this month, everyone in this tree — Bob, Carol, Dave, Eve, and Frank — gets the vote multiplier. This creates a cascading incentive: Bob benefits when Alice leads, so Bob is motivated to help Alice maintain the lead.

The Closure Table Pattern

A naive approach would store edges (parent→child) and use recursive queries to find descendants. That's expensive. Instead, we use a closure table — a precomputed table of every ancestor→descendant relationship with the depth between them.

Now answering "who is in Alice's tree up to depth 3?" is a single flat query:

SELECT descendant_user_id FROM pifster_referral_closure WHERE ancestor_user_id = :alice_id AND depth BETWEEN 1 AND 3

No recursion. No joins. O(1) lookup.

Building the Closure Table

When a new edge is created (Bob refers Carol), we insert the direct edge and compute all ancestor relationships in one SQL statement:

public function createEdge(int $parentUserId, int $childUserId): bool { if ($parentUserId === $childUserId) { return false; // Can't refer yourself } $this->wpdb->query('START TRANSACTION'); try { // Ensure both users have self-closure rows (depth 0) $this->ensureSelfClosureRow($parentUserId); $this->ensureSelfClosureRow($childUserId); // Insert the direct edge $this->wpdb->insert($this->edgesTable, [ 'child_user_id' => $childUserId, 'parent_user_id' => $parentUserId, 'created_at' => current_time('mysql', true), 'verified_at' => current_time('mysql', true), ]); // Propagate closure: all ancestors of parent // become ancestors of child at depth + 1 $this->wpdb->query($this->wpdb->prepare( "INSERT IGNORE INTO {$this->closureTable} (ancestor_user_id, descendant_user_id, depth) SELECT ancestor_user_id, %d, depth + 1 FROM {$this->closureTable} WHERE descendant_user_id = %d AND depth < 3", $childUserId, $parentUserId )); $this->wpdb->query('COMMIT'); return true; } catch (\Throwable $e) { $this->wpdb->query('ROLLBACK'); return false; } }

The key insight is the INSERT ... SELECT for closure propagation. When Bob refers Carol, we find every ancestor of Bob (Alice at depth 1, Bob at depth 0) and create new closure rows pointing to Carol at depth + 1. This single query handles the entire transitive closure update.

We cap depth at 3 to prevent unbounded growth. Three levels of network effects is enough to create interesting dynamics without becoming an MLM.

The Referral Journey

1. Token Provisioning

Every user gets a unique 6-character referral token, auto-generated on registration from a reduced charset (no I/O/0/1):

private const TOKEN_LENGTH = 6; private const TOKEN_ALPHABET = 'ABCDEFGHJKMNPQRSTUVWXYZ23456789'; private function generateToken(int $length): string { $alphabet = self::TOKEN_ALPHABET; $max = strlen($alphabet) - 1; $out = ''; for ($i = 0; $i < $length; $i++) { $out .= $alphabet[random_int(0, $max)]; } return $out; }

2. The Join Link

When someone visits pifster.org/join?ref=K7NP3W, a handler validates the token format, sets a 30-day pifster_ref cookie, and redirects to the registration page. The cookie survives if the visitor doesn't register immediately — they have a month to come back.

3. Registration + Email Verification

When the new user registers and verifies their email via magic link, the ReferralFinalizationListener fires:

  1. Read the pending referral parent from user meta (set during registration from the cookie)
  2. Call createEdge() to insert the edge + update the closure table
  3. Refresh the POM leaderboard cache
  4. Clear the cookie and pending state

The edge isn't created until email verification completes — this prevents fake signups from gaming the leaderboard.

4. Gift Card Auto-Referral

Here's where it connects to gift memberships: when someone buys a gift membership and the recipient redeems it, the purchaser is automatically registered as the referrer — no referral link needed. The gift card is the referral.

The Monthly Leaderboard

The “Parent Always Wins” Problem

There's an inherent flaw in tree-based referral systems: ancestors passively accumulate credit for their descendants' work. In our example tree, if Bob refers 10 people and Carol refers 5, Alice gets credit for all 15 — despite doing nothing new herself. Left unchecked, the earliest adopters permanently dominate the leaderboard simply by having been first.

We solve this with two deliberate constraints:

  1. Rank by direct (depth-1) referrals only. Alice only gets credit for Bob and Frank — the people she personally referred. Bob's and Carol's recruiting efforts earn them ranking points, not Alice.
  2. Reset the scoreboard every month. Last month's POM starts at zero on the 1st, just like a brand-new member. There are no dynasty advantages — the leaderboard is a sprint, not an inheritance.

The tree still matters for who benefits from the multiplier (the entire downline gets boosted vote power), but who earns the crown is purely a function of individual effort in the current month.

The Query

Each month, we rank all referrers for the active period window. The leaderboard query joins the closure table with edges, filtered to verified referrals within the current month's date range:

SELECT c.ancestor_user_id AS user_id, COUNT(*) AS total_verified, SUM(CASE WHEN c.depth = 1 THEN 1 ELSE 0 END) AS direct_referrals, SUM(CASE WHEN c.depth = 2 THEN 1 ELSE 0 END) AS depth2_referrals, SUM(CASE WHEN c.depth = 3 THEN 1 ELSE 0 END) AS depth3_referrals FROM pifster_referral_closure c INNER JOIN pifster_referral_edges e ON e.child_user_id = c.descendant_user_id WHERE c.depth BETWEEN 1 AND 3 AND e.verified_at >= :period_start AND e.verified_at <= :period_end GROUP BY c.ancestor_user_id HAVING direct_referrals > 0 ORDER BY direct_referrals DESC, total_verified DESC LIMIT 10

Ranking rules:

  • Primary sort: direct (depth-1) referrals. You can't game the system by having your referrals refer people — only your personal referrals count for ranking.
  • Tiebreaker: total verified across all depths. If two people have 5 direct referrals each, the one whose network is growing faster ranks higher.
  • Second tiebreaker: earliest last referral. Rewards consistent effort over last-minute sprints.

The Vote Multiplier

Here's where it pays off. When a user casts a vote, the PomVoteMultiplierService checks if they deserve a boost:

public function getDecisionForVoterInPeriod( int $voterUserId, MonthlyData $period ): PomMultiplierDecision { // Is the POM system active this month? if (!$period->pomSystemActive) { return new PomMultiplierDecision(1.0, 'none', 0); } $multiplier = $period->pomVoteMultiplier; // e.g., 2.0 $leaderUserId = $period->currentPomUserId; // Are you the POM leader? if ($voterUserId === $leaderUserId) { return new PomMultiplierDecision( $multiplier, 'pom_leader', $leaderUserId ); } // Are you in the leader's downline (up to depth 3)? $depth = $this->db->get_var($this->db->prepare( "SELECT depth FROM {$closureTable} WHERE ancestor_user_id = %d AND descendant_user_id = %d AND depth BETWEEN 1 AND 3 LIMIT 1", $leaderUserId, $voterUserId )); if ($depth !== null) { return new PomMultiplierDecision( $multiplier, 'pom_downline', $leaderUserId ); } return new PomMultiplierDecision(1.0, 'none', $leaderUserId); }
The incentive design: Your vote power boost comes from being in the winning referral tree, not just from referring people. If your referrer stops leading, you lose the multiplier. This creates cooperative dynamics — the downline is incentivized to help their branch's leader stay on top.

The Profile Dashboard

Users see their referral stats on their profile: current rank, gap to top positions, multiplier status, and proximity messages like "2 personal referrals to take the lead!"

Statuses include:

  • Ready to Rise — you have no referrals yet this month
  • Ranked — you're on the board but not leading
  • Leading — you're the current POM
  • Empty Leaderboard — nobody has referred anyone this month (first-mover advantage!)

What We Deliberately Avoided

  1. Cash rewards. Money incentives corrupt the mission. Influence is the only currency.
  2. Unlimited depth. We cap at 3 levels. Deeper trees create MLM dynamics where early adopters permanently benefit regardless of ongoing effort.
  3. Permanent multipliers. The multiplier resets every month. Last month's POM starts at 1x on the first of the new month, just like everyone else.
  4. Penalizing churn. If someone you referred cancels, your referral still counts. We don't want people pressuring their friends to stay.

Tips If You Build This

  1. Use a closure table, not recursive queries. The closure table trades write-time computation for constant-time reads. Worth it when you're querying the graph on every vote.
  2. Verify before counting. Don't create the referral edge until email verification completes. Fake signups are the first thing gamers try.
  3. Rank by direct referrals, not network size. If you rank by total descendants, early adopters who referred one prolific person get credit for their referral's work.
  4. Cap your depth. 2-3 levels is the sweet spot. Deep enough for cascading incentives, shallow enough to avoid “passive income” dynamics.
  5. Make it visible. The leaderboard, the gap-to-first counter, the multiplier badge — these UI elements do more for engagement than the underlying system.
  6. Cookie the referral early, finalize late. Set the cookie on the join link, but don't create the edge until after email verification. This handles the case where someone clicks the link, browses, leaves, and comes back days later.

PIFster is a community-driven charitable giving platform where donors vote on which charity receives the community's pooled donations each month. We run on WordPress with magic link authentication, pay-what-you-want checkout, and gift memberships for donor acquisition. If you're building something similar, we'd love to hear about it.

About The Author

PIFster Admin

Founder and administrator of PIFster, the Pay It Forward charity. We thank you for being here.
Leave a Reply

Your email address will not be published. Required fields are marked *

    Illustration of three people sitting at a table with colorful speech bubbles above them on a light blue background. Large text in the center reads “Join Newsletter.” Perfect for charity, giving, or help-themed campaigns.
    Footer Form

    © 2026 PIFster. All rights reserved. | PIFster is Veteran Owned & Operated | EIN: 92-1821142