skills/customer-crm/referral-program/SKILL.md
Grow your customer base with a refer-a-friend program featuring unique shareable links, tiered rewards, and built-in fraud prevention
npx skillsauth add finsilabs/awesome-ecommerce-skills referral-programInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A referral program turns your existing customers into an acquisition channel by rewarding them for introducing new customers. Referral apps like ReferralCandy and Referral Hero handle unique link generation, double-sided rewards (referrer and referee), fraud detection, and post-purchase email triggers without custom code. Only build a custom referral system if your tiering logic, CRM integration, or fraud rules exceed what these tools support.
| Platform | Recommended Tool | Why | |----------|-----------------|-----| | Shopify | ReferralCandy | Purpose-built for e-commerce; auto-generates referral links per customer, handles double-sided rewards, post-purchase email trigger, and fraud detection | | Shopify | Referral Hero | More flexible reward types (cash, gift cards, store credit, custom); deep Klaviyo integration for referral email flows | | Shopify | Smile.io | Combines loyalty points with referral mechanics in one app — best when you want both | | WooCommerce | ReferralCandy or Referral Hero | Both offer WooCommerce plugins; connect via REST API to track orders and issue rewards | | BigCommerce | ReferralCandy | Available on the BigCommerce App Marketplace | | Custom / Headless | Build referral tracking + reward logic | Required when platform integrations or fraud rules don't match your needs |
Option A: ReferralCandy (recommended — full referral suite)
Install ReferralCandy from the Shopify App Store
Connect your Shopify store — ReferralCandy automatically imports existing customers
Configure your reward structure:
Configure referral email timing:
ReferralCandy automatically:
View performance in ReferralCandy → Analytics:
Option B: Referral Hero (Klaviyo-first)
Adding a referral entry point in post-purchase emails (Klaviyo):
{{ customer.referral_link }} as a merge tagReferralCandy for WooCommerce:
Referral Hero for WooCommerce:
Manual referral program with AutomateWoo:
ReferralCandy for BigCommerce:
For headless storefronts, build referral tracking with tiered rewards and fraud detection:
// lib/referrals.ts
import { randomBytes } from 'crypto';
// Generate a unique, human-friendly referral code per customer
export async function getOrCreateReferralCode(customerId: string): Promise<string> {
const existing = await db.referralCodes.findFirst({ where: { customerId } });
if (existing) return existing.code;
const customer = await db.customers.findUnique({ where: { id: customerId } });
const prefix = (customer!.firstName ?? 'USER').slice(0, 4).toUpperCase();
const suffix = randomBytes(3).toString('hex').toUpperCase();
const code = `${prefix}${suffix}`; // e.g., JANE3A9F
await db.referralCodes.create({ data: { customerId, code } });
return code;
}
// Middleware: capture referral code from ?ref= URL param into a 30-day cookie
export function referralTrackingMiddleware(req: Request, res: Response, next: NextFunction) {
const code = req.query.ref as string;
if (code && !req.cookies.ref_code) {
res.cookie('ref_code', code, { maxAge: 30 * 86400000, httpOnly: true, secure: true, sameSite: 'lax' });
}
next();
}
// Tiered rewards: reward amount increases as referrer accumulates successful referrals
const REFERRAL_TIERS = [
{ minReferrals: 0, referrerRewardCents: 1000, refereeRewardCents: 1000 }, // $10/$10
{ minReferrals: 5, referrerRewardCents: 1500, refereeRewardCents: 1000 }, // $15/$10 after 5
{ minReferrals: 10, referrerRewardCents: 2500, refereeRewardCents: 1500 }, // $25/$15 after 10
];
function getReferralReward(successfulReferrals: number) {
return [...REFERRAL_TIERS].reverse().find(t => successfulReferrals >= t.minReferrals)!;
}
// On new account creation: attribute referral, run fraud checks
export async function onCustomerCreated(customerId: string, refCode: string | undefined) {
if (!refCode) return;
const referralCode = await db.referralCodes.findFirst({ where: { code: refCode } });
if (!referralCode || referralCode.customerId === customerId) return; // block self-referral
// Fraud check: same shipping address as referrer
const [referee, referrer] = await Promise.all([
db.customers.findUnique({ where: { id: customerId }, include: { addresses: true } }),
db.customers.findUnique({ where: { id: referralCode.customerId }, include: { addresses: true } }),
]);
const refereeAddr = referee?.addresses[0]?.addressHash;
const referrerAddr = referrer?.addresses[0]?.addressHash;
if (refereeAddr && refereeAddr === referrerAddr) return; // same address = block
await db.referrals.create({ data: { referrerId: referralCode.customerId, refereeId: customerId, code: refCode, status: 'pending' } });
}
// On referee's first purchase: issue rewards to both parties
export async function onRefereeFirstPurchase(refereeId: string, orderId: string) {
const referral = await db.referrals.findFirst({ where: { refereeId, status: 'pending' } });
if (!referral) return;
const order = await db.orders.findUnique({ where: { id: orderId } });
if (!order || order.subtotalCents < 2500) return; // require minimum $25 order
const referrerStats = await db.referralCodes.findFirst({ where: { customerId: referral.referrerId } });
const tier = getReferralReward(referrerStats?.totalReferrals ?? 0);
await Promise.all([
issueStoreCredit(referral.referrerId, tier.referrerRewardCents, `Referral reward`),
issueStoreCredit(refereeId, tier.refereeRewardCents, 'Welcome reward — referred by a friend'),
]);
await db.referrals.update({ where: { id: referral.id }, data: { status: 'rewarded', orderId } });
await db.referralCodes.update({ where: { customerId: referral.referrerId }, data: { totalReferrals: { increment: 1 } } });
}
Referral program analytics SQL:
-- Monthly referral program performance
SELECT
DATE_TRUNC('month', r.created_at) AS month,
COUNT(*) AS total_referrals,
COUNT(CASE WHEN r.status = 'rewarded' THEN 1 END) AS successful_referrals,
ROUND(100.0 * COUNT(CASE WHEN r.status = 'rewarded' THEN 1 END) / NULLIF(COUNT(*), 0), 1) AS conversion_rate_pct,
SUM(CASE WHEN r.status = 'rewarded' THEN rc.total_rewards_cents END) / 100.0 AS rewards_paid_usd
FROM referrals r
JOIN referral_codes rc ON r.referrer_id = rc.customer_id
GROUP BY 1
ORDER BY 1 DESC;
The referral link needs to be visible — customers won't find it if it's buried:
| Metric | How to Measure | |--------|---------------| | Referral conversion rate | Successful referrals / total referral clicks | | Referral CAC | Total rewards paid / successful referrals | | Revenue attributed to referrals | Tag referred orders and compare total revenue | | Referred customer CLV vs. non-referred | Cohort comparison at 90 days and 12 months |
Compare referral CAC against your paid acquisition channels. Referral programs typically produce 20–30% lower CAC than paid channels when optimized.
| Problem | Solution | |---------|----------| | Self-referral fraud via multiple email accounts | Block same shipping address referrals (strongest signal); ReferralCandy detects this automatically | | Referral link shared on coupon forums | Monitor referred cohort CLV; if it's significantly lower than organic, apply a higher minimum order value | | Store credit issued before 30-day return window | Delay reward issuance by 30 days after the referee's order to account for returns | | Referral cookie overwritten by later ad click | Store the first referral click separately; ReferralCandy uses first-click attribution for referrals | | Low referral email open rates | Move the referral ask from the receipt email to a dedicated 3-day post-purchase email when customer satisfaction is highest |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion