For my $5.50 lifetime ScsDriver WebDAV mount tool, I have a 7-day trial extendable via successful invite activations. For 8 months I've been tuning the timing of when reward emails go out.
Here are 5 things I tried, and the one pattern that actually moved retention metrics.
Retry 1: Send invite reward instantly on activation
Send the +14-day reward to the inviter the moment the invitee activates.
Result: 31% of rewards went to fake accounts (grinders, link-clickers, single-use emails). Real users churned from the noise.
Verdict: too eager.
Retry 2: Send reward after 24h
Wait 24h after activation to confirm the invitee is still around.
Result: fake rate dropped to 18%. Better. But real users got +14d on their 25th day after activation — by then they had forgotten why.
Verdict: better, but timing still off.
Retry 3: Send reward after 7 days
Wait 7 days. By then, real invitees are still using the product (activation score > 3).
Result: fake rate dropped to 4%. Real-user reward satisfaction jumped because they got the bonus right when they were thinking about renewal.
Verdict: huge improvement. This became my default.
Retry 4: Multi-stage cooldown (3d, 7d, 14d)
I tried splitting the +14d into 3d + 4d + 7d, distributed at 3, 7, 14 days.
Result: perceived as gimmicky. Users said it "felt like watching paint dry" and a few support emails complained about "where's my reward?". The extra tracking complexity also created more bugs.
Verdict: too clever. Stick with single-shot.
Retry 5: Personalized cooldown based on activation score
For invitees with activation_score >= 6, send reward at day 7. For score 3-5, send at day 14. For score < 3, no reward.
Result: this is the one that worked. Fake rate hit 1.8% (down from 4% with single 7-day). Real-user reward satisfaction went from 60% to 84% in survey. Activation score is doing the discrimination work; cooldown timing is doing the user-experience work.
Verdict: this is what I shipped.
The pattern that actually worked
def send_invite_reward(inviter, invitee):
score = compute_activation_score(invitee)
if score < 3:
return # fake, no reward
delay_days = 14 if score < 6 else 7
schedule_email(
to=inviter.email,
template='referral_thanks',
delay=delay_days,
params={'name': inviter.name, 'days': 14}
)
Two factors:
- Activation score gates reward eligibility (catches fake)
- Cooldown days are personalized by score (catches bad UX timing)
Why personalization mattered
Real users with high activation scores don't need 14 days to "confirm" — they're clearly invested by day 7. Real users with mid scores (3-5) benefit from longer confirmation. Splitting them by signal improves both groups' experience.
Fake accounts almost never reach score 3 — they install-and-leave without using the feature surface.
What I learned
- Reward timing matters as much as reward size. Users notice when they get something.
- Splitting a single reward into multi-stage adds perceived complexity without actual benefit.
- Personalization based on real signals (activation) > rule-of-thumb heuristics.
- The boring answer — wait 7 days — got me most of the way. Personalization added the last 20%.
For ScsDriver's referral program, this combination has held up over 8 months with minimal iteration. The activation-score signal does the heavy lifting; timing personalization is the user-experience polish on top.
Top comments (0)