2-minute quickstart
PreLaunch Waitlist works with any HTML form on any platform. You need two things: a form with an email input, and your project ID from the dashboard.
Step 1 — Get your project ID
Sign in to your dashboard, open your project, and copy the Project ID shown at the top of the page.
Step 2 — Add the snippet
Paste this into your HTML, replacing YOUR_PROJECT_ID with the
ID you just copied. Put it just before the closing </body> tag.
<!-- 1. Load the SDK --> <script src="https://prelaunchwaitlist.com/v1/plw.js"></script> <!-- 2. Initialise with your project ID --> <script> PLW.init({ projectId: 'YOUR_PROJECT_ID', formSelector: '#waitlist-form', emailInputSelector: '#email', }); </script>
Step 3 — Make sure your form matches
The selectors in PLW.init() must match the IDs (or classes) of
your actual form elements. Here's the minimal markup:
<form id="waitlist-form"> <input type="email" id="email" placeholder="[email protected]" /> <button type="submit">Join the waitlist</button> </form>
That's it. The SDK intercepts the form submission, sends the email to Pre
Launch Waitlist, and calls your onSuccess or onError
callback when it's done.
How it works
The SDK is a small, dependency-free script (~5 KB gzipped) that attaches to your existing form. When a visitor submits the form:
- The SDK intercepts the submit event and prevents the default page reload.
-
It reads the email from
emailInputSelectorand any extra fields you have configured. - It posts to the PreLaunch Waitlist API, which stores the subscriber, deduplicates, and fires any webhooks you've set up.
- Your
onSuccesscallback is called — update the UI however you like.
Everything runs in the visitor's browser — there is no server-side code to write or maintain on your side.
PLW.init() options
All options accepted by PLW.init():
| Option | Type | Required | Description |
|---|---|---|---|
projectId |
string | Required | Your project ID from the dashboard. |
formSelector |
string | Required | CSS selector for the <form> element, e.g. '#waitlist-form'. |
emailInputSelector |
string | Required | CSS selector for the email <input>, e.g. '#email'. |
onSuccess |
function | Optional | Called after a successful subscription. Receives no arguments. Use this to swap the form for a confirmation message. |
onError |
function | Optional | Called if the subscription fails. Receives an Error object as its first argument. |
metadata |
object | Optional | Arbitrary key/value pairs stored with the subscriber, e.g. { plan: 'pro' }. |
Callbacks
Use onSuccess and onError to give visitors instant
feedback without a page reload.
PLW.init({
projectId: 'YOUR_PROJECT_ID',
formSelector: '#waitlist-form',
emailInputSelector: '#email',
onSuccess() {
document.getElementById('waitlist-form').innerHTML =
'<p>You\'re on the list! We\'ll be in touch. 🎉</p>';
},
onError(err) {
document.getElementById('error-msg').textContent =
'Something went wrong. Please try again.';
console.error(err);
},
});
The onSuccess handler is the right place to fire any analytics
(e.g. gtag('event', 'sign_up')) or show a celebration animation.
Platform guides
The SDK works the same way on every platform. The only difference is where to paste the snippet.
Plain HTML / static sites
Paste the snippet before </body> in your HTML file. Your
form must appear in the DOM before the script runs — putting the snippet at
the end of the body guarantees this.
... <form id="waitlist-form"> <input type="email" id="email" /> <button>Join waitlist</button> </form> <script src="https://prelaunchwaitlist.com/v1/plw.js"></script> <script> PLW.init({ projectId: 'YOUR_PROJECT_ID', formSelector: '#waitlist-form', emailInputSelector: '#email' }); </script> </body>
Next.js
Use Next.js's built-in <Script> component with
strategy="afterInteractive" to load the SDK after the page
hydrates. Then call PLW.init() in a useEffect.
// app/components/WaitlistForm.tsx 'use client'; import Script from 'next/script'; import { useEffect } from 'react'; export default function WaitlistForm() { useEffect(() => { // PLW is added to window by the script below if (typeof window !== 'undefined' && (window as any).PLW) { (window as any).PLW.init({ projectId: 'YOUR_PROJECT_ID', formSelector: '#waitlist-form', emailInputSelector: '#email', onSuccess() { /* show confirmation */ }, }); } }, []); return ( <> <Script src="https://prelaunchwaitlist.com/v1/plw.js" strategy="afterInteractive" onLoad={() => { (window as any).PLW?.init({ /* same options */ }); }} /> <form id="waitlist-form"> <input type="email" id="email" placeholder="[email protected]" /> <button type="submit">Join the waitlist</button> </form> </> ); }
onLoad prop on <Script> as the
primary init point — it fires as soon as the SDK is ready.
Webflow
- In your Webflow project, open Project Settings → Custom Code.
- Paste the snippet into the Footer Code box.
-
In the Designer, add a Form Block. Set the form's ID to
waitlist-formand the email field's ID toemail(Element Settings panel → ID). - Publish your site — the waitlist is live.
#. PreLaunch Waitlist handles the submission, so you
don't need Webflow's form backend.
Framer
- Go to Site Settings → General → Custom Code.
- Paste the snippet into End of <body> tag.
-
Add an Input component and a Button and
wrap them in a Form. In the Properties panel, set the
form ID to
waitlist-formand the input ID toemail.
WordPress
The simplest approach is to use a plugin like Insert Headers and Footers to add the snippet to every page without editing theme files.
- Install and activate Insert Headers and Footers.
- Go to Settings → Insert Headers and Footers.
- Paste the snippet into the Scripts in Footer box and save.
-
On your page, add an HTML block with your form markup, using IDs
waitlist-formandemail.
Single-page apps
In SPAs the DOM can update after the SDK initialises. If your waitlist form is
rendered dynamically (e.g. inside a modal or after a route change) call
PLW.init() again after the form is in the DOM — the SDK is
safe to call multiple times and will rebind cleanly.
// Call whenever the waitlist form is mounted function initWaitlist() { if (!document.querySelector('#waitlist-form')) return; PLW.init({ projectId: 'YOUR_PROJECT_ID', formSelector: '#waitlist-form', emailInputSelector: '#email', onSuccess() { /* … */ }, }); } // React example useEffect(() => { initWaitlist(); }, []); // Vue example onMounted(() => { initWaitlist(); });
Custom form fields
You can capture extra form fields alongside the email. Any named
<input>, <select>, or
<textarea> inside your form is automatically included in
the formData payload and stored with the subscriber.
<form id="waitlist-form"> <input type="email" id="email" name="email" /> <input type="text" name="fullName" /> <select name="role"> <option value="founder">Founder</option> <option value="investor">Investor</option> </select> <button type="submit">Join</button> </form>
Limits: up to 30 extra fields; keys ≤ 100 chars; values ≤ 1 000 chars. Fields are visible in the dashboard and included in CSV exports.
Metadata & UTM
Pass static metadata at init time to tag every subscriber from this embed with the same attributes — useful for multi-tenant apps or A/B tests:
PLW.init({
projectId: 'YOUR_PROJECT_ID',
formSelector: '#waitlist-form',
emailInputSelector: '#email',
metadata: {
variant: 'hero-a',
plan: 'pro',
},
});
UTM parameters (utm_source, utm_medium,
utm_campaign, utm_term, utm_content)
are captured automatically from the page URL — no extra config needed.
Ready to go live?
Your first waitlist project is free. No credit card, no backend — just copy your project ID and paste the snippet.
Start for free