Building a successful product launch starts with creating buzz and anticipation. One of the most effective strategies is implementing a referral system in your waitlist that turns your early users into advocates. In this comprehensive guide, we'll show you how to create a powerful referral waitlist system using waitly-sdk in your Next.js application.
Why Referral Waitlists Work
Before diving into the implementation, let's understand why referral systems are so effective:
Viral Growth: Each new user can potentially bring multiple friends
Higher Quality Leads: People referred by friends are more likely to engage
Social Proof: Referrals create genuine social validation
Cost-Effective: Organic growth with minimal acquisition costs
Companies like Dropbox, Robinhood, and Superhuman have used referral waitlists to build massive user bases before launch.
Setting Up Your Next.js Project with Waitly
Step 1: Install Waitly SDK
First, install the Waitly SDK in your Next.js project:
npm install @go-waitly/waitly-sdk
Step 2: Initialize the Waitly Client
Create a utility file to initialize your Waitly client:
// lib/waitly.js
import { createWaitlyClient } from "@go-waitly/waitly-sdk";
export const waitly = createWaitlyClient({
apiKey: process.env.WAITLY_API_KEY,
waitlistId: process.env.WAITLY_WAITLIST_ID,
});
Don't forget to add your environment variables in .env.local:
WAITLY_API_KEY=your_api_key_here
WAITLY_WAITLIST_ID=your_waitlist_id_here
Building the Referral System Components
Step 3: Create the Waitlist Signup Form
Let's build a signup form that handles referral codes automatically:
// components/WaitlistForm.jsx
import { useState } from 'react';
import { useRouter } from 'next/router';
import { waitly } from '../lib/waitly';
export default function WaitlistForm() {
const [email, setEmail] = useState('');
const [isLoading, setIsLoading] = useState(false);
const [success, setSuccess] = useState(false);
const router = useRouter();
// Extract referral code from URL parameters
const referralCode = router.query.code;
const handleSubmit = async (e) => {
e.preventDefault();
setIsLoading(true);
try {
const entry = await waitly.createWaitlyEntry({
email,
referredByCode: referralCode, // Automatically use referral code from URL
utm: {
utm_source: referralCode ? 'referral' : 'organic',
utm_medium: 'waitlist',
}
});
// Store user data for the success page
localStorage.setItem('waitlist_entry', JSON.stringify(entry));
setSuccess(true);
} catch (error) {
console.error('Error joining waitlist:', error);
alert('Something went wrong. Please try again.');
} finally {
setIsLoading(false);
}
};
if (success) {
return <ReferralSuccess />;
}
return (
<div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold mb-4 text-center">
Join Our Waitlist
</h2>
{referralCode && (
<div className="mb-4 p-3 bg-green-50 border border-green-200 rounded">
<p className="text-green-800 text-sm">
🎉 You've been invited by a friend! You'll get priority access.
</p>
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
className="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500"
/>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50"
>
{isLoading ? 'Joining...' : 'Join Waitlist'}
</button>
</form>
</div>
);
}
Step 4: Build the Referral Success Page
After users join, show them their referral link and encourage sharing:
// components/ReferralSuccess.jsx
import { useState, useEffect } from 'react';
import { waitly } from '../lib/waitly';
export default function ReferralSuccess() {
const [entry, setEntry] = useState(null);
const [copied, setCopied] = useState(false);
const [stats, setStats] = useState({ position: null, total: 0 });
useEffect(() => {
// Get stored entry data
const storedEntry = localStorage.getItem('waitlist_entry');
if (storedEntry) {
const entryData = JSON.parse(storedEntry);
setEntry(entryData);
// Get position and stats
fetchStats(entryData.email);
}
}, []);
const fetchStats = async (email) => {
try {
const [checkResult, totalCount] = await Promise.all([
waitly.checkEmail(email),
waitly.countEntries()
]);
setStats({
position: checkResult.position,
total: totalCount
});
} catch (error) {
console.error('Error fetching stats:', error);
}
};
const copyReferralLink = () => {
navigator.clipboard.writeText(entry.referral_link);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const shareOnTwitter = () => {
const text = `I just joined the waitlist for this amazing new product! Use my referral link to get priority access: ${entry.referral_link}`;
window.open(`https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}`, '_blank');
};
if (!entry) return <div>Loading...</div>;
return (
<div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg text-center">
<div className="mb-6">
<h2 className="text-2xl font-bold text-green-600 mb-2">
🎉 You're In!
</h2>
<p className="text-gray-600">
You're #{stats.position} of {stats.total} on the waitlist
</p>
</div>
<div className="mb-6 p-4 bg-blue-50 rounded-lg">
<h3 className="font-semibold mb-2">Move Up Faster!</h3>
<p className="text-sm text-gray-600 mb-3">
Share your referral link and move up 1 position for each friend who joins
</p>
<div className="flex items-center space-x-2 mb-3">
<input
type="text"
value={entry.referral_link}
readOnly
className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded bg-gray-50"
/>
<button
onClick={copyReferralLink}
className="px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700"
>
{copied ? 'Copied!' : 'Copy'}
</button>
</div>
<div className="flex space-x-2">
<button
onClick={shareOnTwitter}
className="flex-1 bg-blue-400 text-white py-2 px-4 rounded text-sm hover:bg-blue-500"
>
Share on Twitter
</button>
<button
onClick={() => {
if (navigator.share) {
navigator.share({
title: 'Join this awesome waitlist!',
url: entry.referral_link
});
}
}}
className="flex-1 bg-green-500 text-white py-2 px-4 rounded text-sm hover:bg-green-600"
>
Share
</button>
</div>
</div>
<p className="text-xs text-gray-500">
Your referral code: <span className="font-mono">{entry.referral_code}</span>
</p>
</div>
);
}
Step 5: Create a Referral Status Dashboard
Let users track their referral progress:
// components/ReferralDashboard.jsx
import { useState } from 'react';
import { waitly } from '../lib/waitly';
export default function ReferralDashboard() {
const [email, setEmail] = useState('');
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(false);
const checkStatus = async (e) => {
e.preventDefault();
setLoading(true);
try {
const [checkResult, totalCount] = await Promise.all([
waitly.checkEmail(email),
waitly.countEntries()
]);
setUserData({
...checkResult,
totalEntries: totalCount
});
} catch (error) {
console.error('Error checking status:', error);
alert('Email not found in waitlist');
} finally {
setLoading(false);
}
};
return (
<div className="max-w-md mx-auto p-6 bg-white rounded-lg shadow-lg">
<h2 className="text-2xl font-bold mb-4 text-center">
Check Your Status
</h2>
<form onSubmit={checkStatus} className="space-y-4 mb-6">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
className="w-full px-4 py-2 border border-gray-300 rounded-md"
/>
<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:opacity-50"
>
{loading ? 'Checking...' : 'Check Status'}
</button>
</form>
{userData && (
<div className="space-y-4">
<div className="text-center p-4 bg-gray-50 rounded">
<p className="text-2xl font-bold">#{userData.position}</p>
<p className="text-gray-600">of {userData.totalEntries}</p>
</div>
<div className="p-4 bg-blue-50 rounded">
<h3 className="font-semibold mb-2">Your Referral Link:</h3>
<div className="flex items-center space-x-2">
<input
type="text"
value={userData.referral_link || `https://yoursite.com/?code=${userData.referral_code}`}
readOnly
className="flex-1 px-3 py-2 text-sm border border-gray-300 rounded bg-white"
/>
<button
onClick={() => navigator.clipboard.writeText(userData.referral_link)}
className="px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700"
>
Copy
</button>
</div>
</div>
</div>
)}
</div>
);
}
Best Practices for Waitlist Referrals
1. Clear Value Proposition
Explain what users get for referring friends
Show progress towards rewards
Make benefits tangible and immediate
2. Friction-Free Sharing
One-click sharing to social platforms
Pre-written share messages
Multiple sharing options (email, SMS, social)
3. Progress Visualization
Show current position
Display referral count
Progress bars or achievement badges
4. Mobile Optimization
Ensure forms work perfectly on mobile
Use native share APIs when available
Touch-friendly interface elements
Common Pitfalls to Avoid
Complicated Referral Process: Keep it simple - one click to get a link
Unclear Benefits: Users should immediately understand what they gain
Poor Mobile Experience: Most sharing happens on mobile devices
No Progress Feedback: Users need to see their referrals working
Generic Share Messages: Personalize the sharing experience
Conclusion
Implementing a referral system in your Next.js waitlist using Waitly SDK is straightforward and powerful. The headless approach gives you complete control over the user experience while handling the complex backend logic.
Ready to implement your own referral waitlist? Get started with Waitly and turn your users into your best growth channel.
