Two weeks since real launch. Here's what we can see, what we can't, and what we need to set up now.
Rewards is an onboarding program for the Ramp Network mobile app. Users complete missions across four sections, each driving a first-time action. The end goal: complete all missions to unlock a loyalty bonus (0.25 USDC cashback on every future transaction).
| Section | Missions | Reward |
|---|---|---|
| Welcome to Ramp Network | WALLET (connect wallet) | Part of 1.00 USDC |
| Earn with USDC | TOPUP1 (top up $25+), EARN10 (earn 10 days) | 0.75 USDC |
| Discover swaps | SWAP1 (first swap $50+), SWAP3 (3 swaps) | 2.75 USDC |
| Grow your network | INV3 (invite 3), INV7 (invite 7), SEND5 (send to 5) | 1.00 USDC |
| Unlock loyalty bonus | ONBOARD (complete all above) | 1.00 USDC + ongoing cashback |
The reward structure incentivizes the right behavior. Swaps pay the most (2.75 USDC combined) because they're the highest-margin transaction type. The loyalty bonus at the end creates a reason to complete the full journey, not just cherry-pick easy missions.
Mobile app only (by design). Non-EU/EEA (regulatory). Release flag (rewards-feature, ID 10188193) at 100% rollout for eligible users. No holdout group. Created by Jakub Jastrzebski, last modified by Marek Rycerski.
Rewards visitors show dramatically different behavior from the general population:
| Metric | Rewards Visitors | All Users | Multiplier |
|---|---|---|---|
| W1 rolling retention | 59.7% | 8.1% | 7.4x |
| W2 rolling retention | 69.8% | 5.6% | 12.4x |
| Weekly transaction rate | 33.1% | 10.4% | 3.2x |
33.1% of rewards visitors completed a transaction in the week of March 23, compared to 10.4% of the general population.
42% of users who land on the app dashboard navigate to rewards within 30 minutes (Marek's funnel). That's strong discoverability. iOS penetration is 15.7% (1,035 of 6,594 users). Android is 6.3% (424 of 6,710) with identical flag targeting, so the gap is behavioral or UX, not configuration.
The product design supports return visits. The loyalty gauge (3/10) and "Earned" counter create visible progress. "Complete missions in any order" reduces friction. Users see their journey status every time they open rewards.
The causation gap. Whether this is causation or selection bias is unknown. Users who voluntarily navigate to a loyalty feature may already be the most active users. The 7.4x retention multiplier could simply mean "engaged users are engaged." The flag is at 100% with no control group, so there's no clean way to separate the two.
What to do: Modify the rewards-feature flag (Segment 2) from 100% to 50% to create a randomized holdout. Two weeks of data at current volumes should be enough for the primary retention metric. This is the single most important thing to set up.
Users are clearly interested in this section. 57% section-to-action conversion is the highest across the board. They click through, they start. But EARN10 has zero claims across the entire period.
From the app: a user at 1/2 progress on "Earn with USDC" has completed TOPUP1 but not EARN10. This is the exact pattern the aggregate data shows.
EARN10 requires maintaining a $25+ USDC balance for 10 consecutive days. If the balance drops below $25 at any point (withdrawal, price movement), progress is fully deleted. Not decremented. The entire mission event history is wiped via a transactional delete.
Silent destructive resets. From the code (earn-10-days.tracker.ts): the withdrawal handler checks the balance, and if it's below threshold, calls stopTrackingMission. This deletes the MissionEventLogEntity and MissionEntity rows. The backend publishes a user stream event with completedSteps: 0. The frontend receives this and silently refetches. No toast, no message, no explanation. The user's progress bar drops from e.g. 5/10 to 0/10 and they have no idea why.
10 consecutive days is already a high bar for a first-time earn mission. Combined with silent destructive resets, the failure mode is: user deposits, sees progress building over a week, makes a small withdrawal, progress vanishes, user gives up.
Show users why progress reset. "Your balance dropped below $25 USDC. Keep your balance above $25 to maintain your earning streak."
Evaluate whether 10 consecutive days is the right threshold for an onboarding mission. Watch TOPUP1 weekly trend as a leading indicator of deposit behavior.
17 SWAP1 claims in two weeks. Small. The swap section pays the most (2.75 USDC combined) and has 41% section-to-action conversion, so users are engaging with the CTA. But few complete.
The section bundles SWAP1 and SWAP3 under "Discover swaps - 2.75 USDC" so users see the combined reward without necessarily understanding the breakdown.
The question we can't answer: Do the 17 users who completed SWAP1 go on to swap again organically? This is the whole point. If the mission just rewards a swap that would have happened anyway, it's not driving behavior. If it creates a habit (swap 2, 3, 4 after claiming), it's working. There's no post-mission activity tracking to measure this.
Instrument post-claim activity: track transactions after mission completion, excluding the completing transaction itself. Once sample grows, compare swap frequency before and after SWAP1 completion for the same users. Consider merging SWAP3 into SWAP1 or auto-completing it when organic swaps accumulate.
| Mission | Claims | Section Conversion |
|---|---|---|
| INV3 (invite 3) | 0 | "Grow your network": 49% |
| INV7 (invite 7) | 0 | |
| SEND5 (send to 5) | 0 |
49% section-to-action conversion. Second highest. Users click "Add contacts" but nobody completes. Both INV3 and INV7 use the identical CTA text "Add contacts" (code review confirmed in rewards-actions.use-case.ts), which feels redundant.
Social missions are inherently slower than transactional ones. Getting 3 friends to sign up in 2 weeks is ambitious. 7 is unrealistic at this stage. SEND5 (send to 5 different people) is a high bar for someone who just started.
Give it more time. Social missions may convert on a longer timescale. If INV3 starts converting but INV7 doesn't, consider lowering the INV7 threshold or removing it. SEND5 may need a lower target initially.
| What We Can't Measure | Why It Matters | Status |
|---|---|---|
| Causality | The fundamental question: rewards causes activity vs attracts active users | Flag at 100%, no holdout group |
| Program cost | Can't calculate ROI even if we prove impact | Not in Amplitude, Omni, or any pipeline |
| Unclaimed reward rate | Don't know if users are earning and forgetting | Could be derived from Prometheus counters in Grafana |
| Post-mission organic activity | Can't answer "does completing X lead to more X?" | Not instrumented |
| Reward expiration | Don't know how many rewards expire unused | expire() exists but is never called. No cron job. |
| Android gap root cause | 15.7% iOS vs 6.3% Android, identical targeting | Needs UX investigation |
| Issue | Impact |
|---|---|
| EARN10 progress resets silently on withdrawal | Progress bar drops to 0 with no explanation to the user |
| MISSION_INCOMPLETE mapped to 'available' | Green "available" badge on missions that aren't complete |
| REWARD_EXPIRED has no user-facing copy | Warning icon + disabled button, no explanation |
| No post-claim feedback | "Reward claim submitted" toast with no timeline, no receipt |
| Deprecated claim endpoint still in use | Frontend uses POST /rewards/claim with rewardIds[]. New POST /rewards/:id/claim has zero consumers |
Is cashback actually on? "Unlock loyalty bonus" in the product UI is the ONBOARD meta-mission. Cashback (0.25 USDC per transaction) activates per-user when they complete all missions. REWARDS_CASHBACK_AWARDING_ENABLED defaults to false in code and likely gates the system globally. Need to confirm whether it's toggled on in production. If it's off, the loyalty bonus section is promising something that can't be delivered.
amountWei on every reward. Pipe it to Omni so we can calculate program cost.reward_event_total for AWARDED vs CLAIMED) already exist. Someone needs to build a Grafana panel dividing the two.expire() on the reward aggregate exists and works. Nothing calls it. Rewards silently become unclaimable after 90 days while their status stays AWARDED in the database.| Source | What | Scope |
|---|---|---|
| Amplitude (100017324) | page_view, click events, retention, funnels, user properties | New Widget - Production |
| Omni | fct_widget_events, transactions_simplified | March 2026 |
| Marek's dashboard | e-wbjlpksc | Launch markets, properly filtered |
| Flag config | 10188193 | Targeting rules, rollout % |
| Code review | /packages/backend/src/rewards/, /frontend/widget-2/src/features/rewards/ | Two independent reviews |
| Product UI | App screenshots | Current production build |
| Mission | Claims | Status |
|---|---|---|
| WALLET | 115 | Working |
| TOPUP1 | 65 | Working |
| TX1 | 30 | New, needs investigation |
| SWAP1 | 17 | Small but nonzero |
| SWAP3 | 2 | Effectively dead |
| EARN10 | 0 | Blocked (see EARN10 analysis) |
| INV3 | 0 | Too early to call |
| INV7 | 0 | Threshold likely too high |
| SEND5 | 0 | Threshold likely too high |