Skip to content
Tolinku
Tolinku
Sign In Start Free
App Growth · · 6 min read

A/B Testing Referral Incentives

By Tolinku Staff
|
Tolinku referral programs dashboard screenshot for growth blog posts

The right referral incentive can multiply your viral coefficient. The wrong one wastes budget on low-quality users or fails to motivate sharing at all. A/B testing referral incentives tells you exactly which reward type, amount, and structure drives the most high-quality referrals for your app.

For referral reward fundamentals, see Referral Reward Strategies: Finding the Right Incentive. For A/B testing deep links, see A/B Testing Deep Links and Landing Pages.

Tolinku A/B test creation form with type, goal, and variant configuration The A/B test creation form with test type, goal metric, route picker, and variant builder.

What to Test

Incentive Variables

Variable Options Impact
Reward type Cash, credit, free month, feature unlock High
Reward amount $5 vs. $10 vs. $20 High
Reward structure Single-sided vs. double-sided High
Reward timing Immediate vs. after action Medium
Reward visibility Prominent vs. subtle Medium
Referral limit Unlimited vs. capped Low
Expiration None vs. 30 days vs. 7 days Medium

Test Priority

  1. Reward type: Cash vs. credit vs. feature unlock (biggest impact)
  2. Double-sided vs. single-sided: Does rewarding the invitee improve conversion?
  3. Reward amount: Find the minimum effective amount
  4. Timing: Immediate reward vs. after the invitee's first purchase

Reward Type Tests

Cash vs. Credit vs. Feature

const rewardTypeExperiment = {
  id: 'referral_reward_type_v2',
  variants: [
    {
      id: 'cash',
      weight: 25,
      config: {
        referrerReward: { type: 'cash', amount: 10, currency: 'USD' },
        inviteeReward: { type: 'cash', amount: 10, currency: 'USD' },
        displayText: 'Give $10, Get $10',
      },
    },
    {
      id: 'credit',
      weight: 25,
      config: {
        referrerReward: { type: 'credit', amount: 15, currency: 'USD' },
        inviteeReward: { type: 'credit', amount: 15, currency: 'USD' },
        displayText: 'Give $15, Get $15 in credit',
      },
    },
    {
      id: 'feature',
      weight: 25,
      config: {
        referrerReward: { type: 'feature', feature: 'premium_month', value: 9.99 },
        inviteeReward: { type: 'feature', feature: 'premium_month', value: 9.99 },
        displayText: 'Give a free month, Get a free month',
      },
    },
    {
      id: 'points',
      weight: 25,
      config: {
        referrerReward: { type: 'points', amount: 500, value: 5 },
        inviteeReward: { type: 'points', amount: 500, value: 5 },
        displayText: 'Give 500 points, Get 500 points',
      },
    },
  ],
  primaryMetric: 'referral_sent',
  secondaryMetrics: ['referral_converted', 'invitee_d30_retention', 'reward_cost_per_acquisition'],
};

Typical results by app type:

App Type Best Reward Type Why
E-commerce Cash or credit Direct purchasing power
SaaS/Subscription Free month Aligns with the product
Gaming In-game currency Matches user motivation
Fintech Cash Users are money-motivated
Social Feature unlock Status/access is the currency

Amount Sensitivity

const rewardAmountExperiment = {
  id: 'referral_amount_v1',
  variants: [
    {
      id: 'low',
      weight: 33,
      config: {
        referrerReward: { type: 'credit', amount: 5 },
        inviteeReward: { type: 'credit', amount: 5 },
        displayText: 'Give $5, Get $5',
      },
    },
    {
      id: 'medium',
      weight: 33,
      config: {
        referrerReward: { type: 'credit', amount: 10 },
        inviteeReward: { type: 'credit', amount: 10 },
        displayText: 'Give $10, Get $10',
      },
    },
    {
      id: 'high',
      weight: 34,
      config: {
        referrerReward: { type: 'credit', amount: 20 },
        inviteeReward: { type: 'credit', amount: 20 },
        displayText: 'Give $20, Get $20',
      },
    },
  ],
  primaryMetric: 'referral_converted',
  secondaryMetrics: ['referral_sent', 'cost_per_acquisition', 'invitee_ltv'],
};

Important: Don't just look at referral volume. Calculate cost per acquired user:

function calculateReferralROI(variantResults) {
  const { referralsSent, referralsConverted, rewardAmount, inviteeLTV } = variantResults;

  const conversionRate = referralsConverted / referralsSent;
  const totalRewardCost = referralsConverted * rewardAmount * 2; // Both sides
  const costPerAcquisition = totalRewardCost / referralsConverted;
  const roi = (inviteeLTV - costPerAcquisition) / costPerAcquisition;

  return {
    conversionRate: (conversionRate * 100).toFixed(1) + '%',
    costPerAcquisition: '$' + costPerAcquisition.toFixed(2),
    roi: (roi * 100).toFixed(0) + '%',
    isPositiveROI: roi > 0,
  };
}

Higher rewards increase volume but also increase cost. The optimal amount is the one that maximizes (referrals x LTV) - (referrals x reward cost).

Structure Tests

Double-Sided vs. Single-Sided

const structureExperiment = {
  id: 'referral_structure_v1',
  variants: [
    {
      id: 'referrer_only',
      weight: 33,
      config: {
        referrerReward: { type: 'credit', amount: 10 },
        inviteeReward: null,
        displayText: 'Get $10 for every friend you invite',
        shareMessage: 'Check out [App]!',
      },
    },
    {
      id: 'invitee_only',
      weight: 33,
      config: {
        referrerReward: null,
        inviteeReward: { type: 'credit', amount: 10 },
        displayText: 'Give your friends $10 off',
        shareMessage: 'Here\'s $10 off [App]!',
      },
    },
    {
      id: 'double_sided',
      weight: 34,
      config: {
        referrerReward: { type: 'credit', amount: 10 },
        inviteeReward: { type: 'credit', amount: 10 },
        displayText: 'Give $10, Get $10',
        shareMessage: 'We both get $10 when you join [App]!',
      },
    },
  ],
  primaryMetric: 'referral_converted',
  secondaryMetrics: ['referral_sent', 'invitee_d7_retention', 'cost_per_acquisition'],
};

Typical results:

Structure Referrals Sent Conversion Rate Best For
Referrer only High Lower Driving volume
Invitee only Lower Higher Quality conversions
Double-sided Highest Highest Most apps (standard)

Double-sided programs outperform single-sided by 25-40% on total conversions in most categories.

Asymmetric Rewards

const asymmetricExperiment = {
  id: 'asymmetric_reward_v1',
  variants: [
    {
      id: 'equal',
      weight: 33,
      config: {
        referrerReward: 10,
        inviteeReward: 10,
        displayText: 'Give $10, Get $10',
      },
    },
    {
      id: 'referrer_more',
      weight: 33,
      config: {
        referrerReward: 15,
        inviteeReward: 5,
        displayText: 'Earn $15 for each friend ($5 for them)',
      },
    },
    {
      id: 'invitee_more',
      weight: 34,
      config: {
        referrerReward: 5,
        inviteeReward: 15,
        displayText: 'Give friends $15, you get $5',
      },
    },
  ],
  primaryMetric: 'referral_converted',
};

Invitee-weighted rewards typically produce higher conversion rates (the invitee has more motivation to complete signup). Referrer-weighted rewards produce more shares (the referrer is more motivated to send). For most apps, equal rewards perform best overall.

Timing Tests

Immediate vs. Delayed Rewards

const timingExperiment = {
  id: 'reward_timing_v1',
  variants: [
    {
      id: 'immediate',
      weight: 50,
      config: {
        referrerRewardTrigger: 'invitee_signup',
        inviteeRewardTrigger: 'signup',
        displayText: 'Get $10 instantly when your friend signs up',
      },
    },
    {
      id: 'after_action',
      weight: 50,
      config: {
        referrerRewardTrigger: 'invitee_first_purchase',
        inviteeRewardTrigger: 'first_purchase',
        displayText: 'Get $10 when your friend makes their first purchase',
      },
    },
  ],
  primaryMetric: 'referral_sent',
  secondaryMetrics: ['referral_converted', 'invitee_first_purchase', 'fraud_rate'],
};
Timing Shares Conversions Fraud Risk User Quality
Immediate (on signup) Higher Higher Higher Lower
Delayed (on first purchase) Lower Lower volume, higher quality Lower Higher

Delayed rewards reduce fraud significantly but also reduce volume. For subscription apps, rewarding on "completed first billing cycle" produces the highest quality referrals.

async function generateReferralLink(referrerId, experimentId) {
  const variant = assignVariant(referrerId, experimentId);

  const deepLink = await createDeepLink({
    path: '/referral',
    params: {
      ref: referrerId,
      experimentId,
      variantId: variant.id,
      reward: JSON.stringify(variant.config.inviteeReward),
    },
    fallbackUrl: `https://example.com/invite?ref=${referrerId}`,
  });

  return {
    url: deepLink,
    shareMessage: variant.config.shareMessage.replace('[App]', 'AppName'),
    displayText: variant.config.displayText,
  };
}

Invitee Landing Page

function ReferralLandingPage({ params }) {
  const variant = getVariantConfig(params.experimentId, params.variantId);

  return (
    <Page>
      <Heading>
        {params.referrerName} invited you to join
      </Heading>

      {variant.inviteeReward && (
        <RewardBanner>
          {formatReward(variant.inviteeReward)}
        </RewardBanner>
      )}

      <CTAButton
        href={appStoreLink}
        onClick={() => trackReferralClick(params)}
      >
        {variant.ctaText || 'Get the App'}
      </CTAButton>
    </Page>
  );
}

Tracking and Analysis

Event Schema

// Referral link shared
analytics.track('referral_shared', {
  experimentId,
  variantId,
  referrerId,
  shareMethod: 'whatsapp', // or 'sms', 'email', 'copy_link', 'twitter'
});

// Invitee clicked referral link
analytics.track('referral_clicked', {
  experimentId,
  variantId,
  referrerId,
  inviteeDevice: deviceType,
});

// Invitee signed up
analytics.track('referral_signup', {
  experimentId,
  variantId,
  referrerId,
  inviteeId,
  timeFromClick: timeDeltaMs,
});

// Reward earned
analytics.track('referral_reward_earned', {
  experimentId,
  variantId,
  userId, // Could be referrer or invitee
  rewardType: 'credit',
  rewardAmount: 10,
  side: 'referrer', // or 'invitee'
});

Full Funnel Analysis

async function referralFunnelAnalysis(experimentId) {
  for (const variant of getVariants(experimentId)) {
    const eligible = await countUsers({ experimentId, variantId: variant.id });
    const shared = await countEvents('referral_shared', { variantId: variant.id });
    const clicked = await countEvents('referral_clicked', { variantId: variant.id });
    const signedUp = await countEvents('referral_signup', { variantId: variant.id });
    const purchased = await countEvents('referral_first_purchase', { variantId: variant.id });
    const rewardCost = await sumField('referral_reward_earned', 'rewardAmount', { variantId: variant.id });
    const inviteeLTV = await avgField('user_ltv', { referralVariant: variant.id });

    console.log(variant.id, {
      shareRate: (shared / eligible * 100).toFixed(1) + '%',
      clickRate: (clicked / shared * 100).toFixed(1) + '%',
      signupRate: (signedUp / clicked * 100).toFixed(1) + '%',
      purchaseRate: (purchased / signedUp * 100).toFixed(1) + '%',
      costPerAcquisition: '$' + (rewardCost / signedUp).toFixed(2),
      avgInviteeLTV: '$' + inviteeLTV.toFixed(2),
      roi: (((inviteeLTV * signedUp) - rewardCost) / rewardCost * 100).toFixed(0) + '%',
    });
  }
}

Common Pitfalls

1. Optimizing for Volume Instead of Quality

A $50 reward will generate more referrals than a $5 reward, but many of those referred users will only sign up for the reward and never return.

Track invitee D30 retention and LTV, not just signup count.

2. Ignoring Fraud

High-value rewards attract fraud (self-referrals, fake accounts):

function detectReferralFraud(referral) {
  const signals = [];

  // Same device fingerprint
  if (referral.referrerDevice === referral.inviteeDevice) {
    signals.push('same_device');
  }

  // Same IP address
  if (referral.referrerIP === referral.inviteeIP) {
    signals.push('same_ip');
  }

  // Rapid completion (clicked and signed up in < 30 seconds)
  if (referral.timeToSignup < 30000) {
    signals.push('too_fast');
  }

  // Referrer has many referrals with low retention
  if (referral.referrerReferralCount > 10 && referral.referrerInviteeRetention < 0.1) {
    signals.push('low_quality_referrer');
  }

  return {
    isSuspicious: signals.length >= 2,
    signals,
  };
}

3. Not Testing the Share Message

The incentive matters, but so does how it's communicated:

const shareMessageTest = {
  id: 'share_message_v1',
  variants: [
    {
      id: 'generic',
      shareMessage: 'Check out this app!',
    },
    {
      id: 'reward_focused',
      shareMessage: 'Use my link and we both get $10!',
    },
    {
      id: 'personal',
      shareMessage: 'I\'ve been using this app and thought you\'d like it. We both get $10 if you sign up.',
    },
  ],
  primaryMetric: 'referral_clicked',
};

Best Practices

  1. Test reward type before amount: Whether you offer cash, credit, or features matters more than the dollar value.
  2. Default to double-sided: Start with equal rewards for both sides unless you have data suggesting otherwise.
  3. Track LTV, not just signups: A $20 reward that attracts users with $100 LTV is better than a $5 reward that attracts users with $10 LTV.
  4. Delay rewards to reduce fraud: Rewarding on first purchase or first week of activity filters out low-quality referrals.
  5. Run for at least 30 days: Referral experiments need time for invitees to sign up, activate, and show retention patterns.
  6. Segment by referrer behavior: Power referrers (5+ referrals) may respond differently to incentive changes than casual sharers.

For A/B testing features, see Tolinku A/B testing. For referral setup, see the referral docs and the A/B testing docs.

Get deep linking tips in your inbox

One email per week. No spam.

Ready to add deep linking to your app?

Set up Universal Links, App Links, deferred deep linking, and analytics in minutes. Free to start.