How to Build a Waitlist That Generates Buzz Before Launch
A waitlist is not just an email collection form. Done well, it is a growth engine that validates demand, builds an audience, and gives you a running start on launch day. Done poorly, it is a graveyard of email addresses that never convert.
We have helped launch several products at Threshline — from MindHyv to JustTheRip — and pre-launch waitlists have been part of our playbook since the beginning. Here is how to build one that actually generates momentum.
Why a Waitlist Works
Before we get into tactics, it helps to understand why waitlists work psychologically.
Scarcity creates value. When something is not available yet, people want it more. A waitlist signals that you are building something worth waiting for. It reframes “we are not ready” as “you are early.”
Commitment drives conversion. Someone who gives you their email address has made a micro-commitment. They are more likely to engage when you launch than someone who sees a cold ad. Studies on commitment and consistency bias back this up — people follow through on small actions they have already taken.
Social proof compounds. “Join 2,347 others on the waitlist” is a powerful signal. Every new signup makes the next signup more likely. It is a flywheel.
You get a feedback channel. A waitlist is not just outbound. It is a two-way channel. You can survey waitlist members about features, pricing, and pain points before you build. We talked about using early user feedback to shape products in our post on building software people actually use.

The Landing Page: One Job, Done Well
Your waitlist landing page has exactly one job: get the email. Everything on the page should drive toward that action.
Here is what the page needs:
A clear headline that communicates what the product does and who it is for. Not clever. Not vague. Direct. “Invoice clients in 30 seconds” beats “The future of freelance finance.”
A one-paragraph description that expands on the headline. What problem does this solve? What makes your approach different? Three to four sentences maximum.
Social proof if you have it. “From the team behind X” or “Backed by Y” or even “Built by engineers who spent 5 years building products for startups” works.
A single email input with a clear CTA button. “Join the Waitlist” is fine. “Get Early Access” is better — it implies they are getting something, not just waiting.
No navigation. No links to other pages. No footer full of distractions. One page, one action.
Here is a minimal waitlist page built with Astro and Tailwind:
---
// src/pages/index.astro
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>ProductName — Tagline Here</title>
</head>
<body class="bg-neutral-950 text-white min-h-screen flex items-center justify-center px-6">
<main class="max-w-xl text-center">
<h1 class="text-4xl font-bold tracking-tight sm:text-5xl">
Invoice clients in 30 seconds
</h1>
<p class="mt-6 text-lg text-neutral-400 leading-relaxed">
A dead-simple invoicing tool built for freelancers who hate
invoicing. Create, send, and track payments without the
bloat of enterprise billing software.
</p>
<form
id="waitlist-form"
class="mt-10 flex flex-col sm:flex-row gap-3 justify-center"
>
<input
type="email"
name="email"
required
placeholder="[email protected]"
class="px-4 py-3 rounded-lg bg-neutral-900 border border-neutral-800
text-white placeholder:text-neutral-500 focus:outline-none
focus:ring-2 focus:ring-blue-500 flex-1 max-w-sm"
/>
<button
type="submit"
class="px-6 py-3 rounded-lg bg-blue-600 font-semibold
hover:bg-blue-500 transition-colors cursor-pointer"
>
Get Early Access
</button>
</form>
<p id="waitlist-count" class="mt-4 text-sm text-neutral-500">
Join 0 others on the waitlist
</p>
</main>
<script>
const form = document.getElementById("waitlist-form") as HTMLFormElement;
const countEl = document.getElementById("waitlist-count");
// Fetch current count on load
async function loadCount() {
const res = await fetch("/api/waitlist/count");
const { count } = await res.json();
if (countEl) countEl.textContent = `Join ${count.toLocaleString()} others on the waitlist`;
}
loadCount();
form.addEventListener("submit", async (e) => {
e.preventDefault();
const formData = new FormData(form);
const email = formData.get("email") as string;
const res = await fetch("/api/waitlist", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email }),
});
if (res.ok) {
form.innerHTML = `
<p class="text-green-400 text-lg font-semibold">
You are on the list. Check your email.
</p>
`;
}
});
</script>
</body>
</html>
The Backend: Supabase for Waitlist Data
You need somewhere to store emails, track referrals, and serve the waitlist count. Supabase handles all of this with minimal setup.
First, create the waitlist table:
create table waitlist (
id uuid default gen_random_uuid() primary key,
email text unique not null,
referral_code text unique not null,
referred_by text references waitlist(referral_code),
referral_count int default 0,
created_at timestamptz default now()
);
-- Index for fast lookups
create index idx_waitlist_email on waitlist(email);
create index idx_waitlist_referral_code on waitlist(referral_code);
-- Row Level Security
alter table waitlist enable row level security;
-- Only allow inserts from the API (no direct client access)
create policy "No direct access" on waitlist for all using (false);
Now the API endpoint that handles signups:
// src/pages/api/waitlist.ts
import type { APIRoute } from "astro";
import { createClient } from "@supabase/supabase-js";
import { nanoid } from "nanoid";
const supabase = createClient(
import.meta.env.SUPABASE_URL,
import.meta.env.SUPABASE_SERVICE_KEY
);
export const POST: APIRoute = async ({ request }) => {
const { email, ref } = await request.json();
if (!email || !email.includes("@")) {
return new Response(JSON.stringify({ error: "Invalid email" }), {
status: 400,
});
}
const referralCode = nanoid(8);
const { error } = await supabase.from("waitlist").insert({
email: email.toLowerCase().trim(),
referral_code: referralCode,
referred_by: ref || null,
});
if (error) {
if (error.code === "23505") {
return new Response(
JSON.stringify({ error: "Already on the waitlist" }),
{ status: 409 }
);
}
return new Response(JSON.stringify({ error: "Something went wrong" }), {
status: 500,
});
}
// Increment referrer's count
if (ref) {
await supabase.rpc("increment_referral_count", { code: ref });
}
// TODO: Send welcome email via Resend/Postmark
return new Response(
JSON.stringify({ referralCode }),
{ status: 201 }
);
};
And a simple count endpoint:
// src/pages/api/waitlist/count.ts
import type { APIRoute } from "astro";
import { createClient } from "@supabase/supabase-js";
const supabase = createClient(
import.meta.env.SUPABASE_URL,
import.meta.env.SUPABASE_SERVICE_KEY
);
export const GET: APIRoute = async () => {
const { count } = await supabase
.from("waitlist")
.select("*", { count: "exact", head: true });
return new Response(JSON.stringify({ count: count ?? 0 }));
};
The Supabase RPC function for incrementing referral counts:
create or replace function increment_referral_count(code text)
returns void as $$
update waitlist
set referral_count = referral_count + 1
where referral_code = code;
$$ language sql security definer;
Referral Mechanics: The Growth Loop
A waitlist without a referral mechanism is just a signup form. The referral loop is what turns it into a growth engine.
The concept is simple: after someone signs up, give them a unique referral link. When their friends sign up using that link, the original user moves up the waitlist or unlocks rewards.
Tier-based rewards work best. Here is a structure we have used:
- 3 referrals: Early access (first wave of beta invites)
- 10 referrals: Lifetime discount (20% off the first year)
- 25 referrals: Founding member badge + input on the roadmap
After signup, redirect to a share page that shows their referral link and current stats:
---
// src/pages/waitlist/share.astro
---
<main class="max-w-lg mx-auto py-20 px-6 text-center">
<h1 class="text-3xl font-bold">You are on the list</h1>
<p class="mt-4 text-neutral-400">
Move up by sharing your referral link.
</p>
<div class="mt-8 p-4 bg-neutral-900 rounded-lg">
<p class="text-sm text-neutral-500 mb-2">Your referral link</p>
<div class="flex gap-2">
<input
id="referral-link"
readonly
class="flex-1 px-3 py-2 bg-neutral-800 rounded text-sm text-white"
/>
<button
id="copy-btn"
class="px-4 py-2 bg-blue-600 rounded text-sm font-semibold
hover:bg-blue-500 transition-colors"
>
Copy
</button>
</div>
</div>
<div class="mt-6 grid grid-cols-3 gap-4 text-center">
<div class="p-4 bg-neutral-900 rounded-lg">
<p id="referral-count" class="text-2xl font-bold">0</p>
<p class="text-xs text-neutral-500 mt-1">Referrals</p>
</div>
<div class="p-4 bg-neutral-900 rounded-lg">
<p id="position" class="text-2xl font-bold">-</p>
<p class="text-xs text-neutral-500 mt-1">Position</p>
</div>
<div class="p-4 bg-neutral-900 rounded-lg">
<p class="text-2xl font-bold">3</p>
<p class="text-xs text-neutral-500 mt-1">Until Early Access</p>
</div>
</div>
<div class="mt-8">
<p class="text-sm text-neutral-500 mb-3">Share directly</p>
<div class="flex gap-3 justify-center">
<a id="share-twitter" class="px-4 py-2 bg-neutral-800 rounded hover:bg-neutral-700 text-sm">
Twitter/X
</a>
<a id="share-linkedin" class="px-4 py-2 bg-neutral-800 rounded hover:bg-neutral-700 text-sm">
LinkedIn
</a>
<a id="share-whatsapp" class="px-4 py-2 bg-neutral-800 rounded hover:bg-neutral-700 text-sm">
WhatsApp
</a>
</div>
</div>
</main>
The key insight with referrals: make the reward visible and the progress tangible. People need to see that sharing actually moves them forward. A progress bar toward the next tier is more motivating than a static number.

The Email Sequence: Stay Top of Mind
Most waitlists collect the email and then go silent until launch. That is a mistake. By launch day, half your waitlist has forgotten they signed up.
Here is a five-email drip sequence that keeps people engaged:
Email 1 (Immediately after signup): Welcome + referral link. Confirm they are on the list, explain how the referral tiers work, and include their unique link. Keep it short.
Email 2 (Day 3): The problem story. Share why you are building this product. What frustrated you? What is broken about the current options? This builds emotional investment.
Email 3 (Day 7): Behind the scenes. Share a screenshot, a design mockup, or a short video of the product in development. People love seeing how the sausage is made. This is where you turn passive subscribers into fans.
Email 4 (Day 14): Social proof update. “We just crossed 1,000 signups” or “Here is what people are saying about us.” Include a testimonial from a beta tester if you have one. Remind them about the referral program.
Email 5 (1 week before launch): The countdown. Build anticipation. Announce the launch date. Tell them what to expect. Give early access details to top referrers.
After the sequence, send monthly updates until launch. Do not go dark. Every month without communication loses you subscribers — both to unsubscribes and to apathy.

Converting Waitlist to Customers
The waitlist is not the goal. Conversions are. Here is how to maximize the transition from “interested” to “paying.”
Launch in waves, not all at once. Invite your top referrers first, then the next tier, then the rest. This creates urgency (“spots are limited in this wave”) and lets you onboard users gradually so you can handle support.
Give waitlist members a real advantage. A discount, an extended trial, or a feature that is only available to early adopters. The advantage needs to be concrete and time-limited. “20% off for the first year if you activate within 48 hours” works. “Early access” alone does not — everyone gets access eventually.
Make onboarding frictionless. When someone clicks the invite link, they should be able to create an account and see value within five minutes. If your onboarding takes 30 minutes of configuration, you will lose people who were excited three months ago but are now lukewarm. We wrote about reducing friction in onboarding flows — it matters even more for waitlist conversions.
Ask for feedback immediately. Your first users are your most engaged. Send a short survey after their first week. Ask what is working, what is confusing, and what is missing. This feedback shapes your post-launch roadmap.
What Not to Do
A few anti-patterns we have seen:
Do not fake the count. It is tempting to start the counter at 500. Do not. If someone refers a friend and the count does not go up, you have lost trust permanently. Start at zero. Real momentum builds faster than you think.
Do not ask for too much information. Name, email, and optionally a referral code. That is it. Every additional field reduces conversions. You can survey people after they are on the list.
Do not build the waitlist page for two weeks. It is a landing page with a form. It should take a day, maybe two with the referral system. Spend your time on the actual product.
Do not wait until the product is “ready” to start the waitlist. The best time to launch a waitlist is when you have the core idea and a rough timeline. You do not need a working product. You need a compelling pitch.
Measuring Success
Track these metrics for your waitlist:
- Signup rate: What percentage of landing page visitors join? Below 20% means your page or messaging needs work.
- Referral rate: What percentage of signups refer at least one person? Above 15% is strong.
- Viral coefficient: Average referrals per signup. Above 1.0 means exponential growth (rare, but possible).
- Email open rate: For your drip sequence. Below 40% means your subject lines need work.
- Conversion rate: What percentage of waitlist members become paying customers? This is the number that matters most. Aim for 15-30%.
Ship It
A waitlist is one of the highest-leverage things you can build before your product is ready. It validates demand, builds an audience, creates a feedback channel, and gives you momentum on launch day.
The technical implementation is straightforward — we showed you the full stack above in under 200 lines of code. The hard part is the messaging: articulating what you are building and why someone should care enough to give you their email address.
Get that right, and the rest follows.
If you are planning a product launch and want help building a waitlist that actually converts, reach out at [email protected]. We have launched enough products to know what works.