Features Pricing
Start My Free Trial

Signup Form

How the public signup form works and what happens when someone joins.

How Signups Work

When someone submits the signup form, the following happens:

  1. Waitlist status check — if the waitlist is closed, the signup is rejected with a 403 error
  2. Bot check — a hidden honeypot field catches automated submissions (bots get a fake success response and no further processing occurs)
  3. Consent check — if the waitlist requires consent, the consent field must be truthy or the signup is rejected with 400 VALIDATION_ERROR (with a consent field error in the errors array)
  4. Validation — email format, required fields, domain restrictions, and custom question answers are checked
  5. Duplicate check — if the email already exists on this waitlist, the existing signup data is returned (no duplicate created)
  6. Atomic creation — a database transaction atomically increments the signup counter and creates the signup record (including consent records if applicable)
  7. Referral credit — if a referred_by_token was included, the referrer’s count is incremented and their position is boosted by the configured referral boost amount
  8. Referral notification — if enabled, the referrer receives an email about the new signup (rate-limited to 1/hour)
  9. Analytics — daily signup counters and UTM counters are updated in the background
  10. Notifications — webhooks, Slack, and Discord notifications fire in the background

The signup receives:

  • Their position on the waitlist
  • A unique referral token they can share to move up
  • The total signup count

Hosted Signup Page

Every waitlist has a hosted page at:

https://makeemwait.com/waitlist.html?id=YOUR_WAITLIST_ID

The page automatically loads the waitlist configuration and renders the form with your custom headline, subheadline, hero image, and questions.

To pre-fill a referral, append the ref parameter:

https://makeemwait.com/waitlist.html?id=YOUR_ID&ref=REFERRAL_TOKEN

When someone signs up through a referral link, the referrer automatically gets credit.

UTM Tracking

The signup form automatically captures UTM parameters from the page URL:

?utm_source=twitter&utm_medium=social&utm_campaign=launch&utm_term=waitlist&utm_content=hero

The supported UTM parameters are utm_source, utm_medium, utm_campaign, utm_term, and utm_content. These are stored with the signup and available in CSV exports and the API. Pro users can view UTM breakdowns in Analytics.

Each UTM field is sanitized before storage: values are truncated to a maximum of 200 characters and any control characters (non-printable characters like null bytes, tabs, or newlines) are stripped. This keeps data clean in exports.

Automatic Data Capture

In addition to the fields the user fills in, the signup form automatically captures two pieces of contextual data with every submission:

Device type — The API classifies the visitor’s device based on their User-Agent header. The device_type field is stored with the signup record and will be one of:

Value Detected When
desktop Default — standard browsers on laptops and desktops
mobile iPhones, Android phones, Opera Mini, Windows Phone, BlackBerry
tablet iPads, Android tablets, Kindle, Silk browser
unknown No User-Agent header present

Timezone — The visitor’s timezone is captured client-side using Intl.DateTimeFormat().resolvedOptions().timeZone (e.g., "America/New_York", "Europe/London") and sent in the timezone field of the signup request. This happens automatically in the hosted signup page, the embeddable widget, and the plain embed. The timezone is stored with the signup record and is visible in Pro analytics charts.

Validation

The signup endpoint validates all incoming data before creating a record. The following limits apply:

Field Max Length Notes
email 320 characters Must be a valid email format
first_name 100 characters Required when waitlist has name_field: "required"
last_name 100 characters Required when waitlist has name_field: "required"
phone 20 characters Required when waitlist has phone_field: "required"
custom_answers 1,000 characters per answer Must match question type (dropdown answers must be a valid option)
UTM fields 200 characters each Control characters are stripped; 5 fields max

Required custom questions must have a non-empty answer. Dropdown-type custom questions must have an answer that matches one of the predefined options.

Duplicate Signup Behavior

If someone submits the signup form with an email that already exists on the waitlist, the API does not return an error. Instead, it returns the existing signup data with an HTTP 200 status code (rather than the 201 used for new signups). No duplicate record is created, no analytics are incremented, and no webhooks fire.

This makes the signup endpoint idempotent — submitting the same email multiple times is safe and always returns the same result. This is useful when:

  • A user accidentally submits the form twice
  • The form is re-submitted after a network timeout
  • You’re building a “check my status” flow that reuses the signup endpoint

Bot Protection

Every signup form includes a hidden website field (honeypot). It’s invisible to real users but gets filled in by bots. When the honeypot is triggered:

  • The bot receives a fake 201 response with fabricated data (a fake referral token, position 1, referral count 0, and the current timestamp)
  • No actual signup record is created
  • No analytics or webhooks fire
  • No validation is performed on the other fields

The fake response is indistinguishable from a real success response, so bots have no way to know they were caught. This happens transparently — no CAPTCHAs or friction for real users.

For additional bot protection, you can also enable reCAPTCHA v3 — an invisible scoring system that detects sophisticated bots without any user interaction. See reCAPTCHA v3 Bot Protection in the Security docs for setup details.

Domain Restrictions (Advanced+)

You can restrict who can sign up by email domain:

  • Allowed email domains — only accept signups from specific domains (e.g., company.com, university.edu)
  • Exclude personal emails — block free email providers like Gmail, Yahoo, Hotmail, etc.

These are configured in your waitlist settings.

!
Advanced Plan Required Domain restrictions require an Advanced plan or higher. On lower tiers, attempting to set these settings returns a tier gating error.

Custom Redirect URL (Advanced+)

Instead of showing the default success page after signup, you can redirect signups to your own URL — for example, a thank-you page, onboarding flow, or external site.

Set the Redirect URL in your waitlist settings. The URL must be HTTPS and no longer than 500 characters.

When a redirect URL is set, the following query parameters are appended automatically:

Parameter Description
position The signup’s position on the waitlist
referral_token Their unique referral token for sharing
total_signups Total number of signups on the waitlist

Example redirect:

https://yoursite.com/thank-you?position=42&referral_token=f7a3b2c1&total_signups=500

This works on both the hosted signup page and the embeddable widget. When no redirect URL is set, the default behavior is used (success page for hosted, inline success message for widget).

!
Advanced Plan Required Custom redirect URLs require an Advanced plan or higher.

Email Verification (Pro)

!
Pro Plan Required Email verification requires a Pro plan.

When require_email_verification is enabled on a waitlist, signups receive a verification email with a clickable link after joining. Clicking the link verifies their address automatically.

How It Works

  1. When a signup is created, a secure verification token (64 hex characters from 32 random bytes) is generated and stored with the signup record
  2. A verification email is sent in the background with a link to verify.html containing the waitlist ID, email, and token as query parameters
  3. When the user clicks the link, the verify page calls the API to confirm the token
  4. On success, the email_verified field is set to true and the verification_token is removed from the record
  5. If the email was already verified, the API returns success with the message “Email already verified”

Verification Fields

The signup record tracks:

  • email_verified — whether the email has been confirmed (true or absent)
  • verification_token — a unique token embedded in the verification link (removed after successful verification)

API Endpoints

Both POST and GET are supported:

GET  /public/waitlists/{id}/signups/{email}/verify?token=TOKEN
POST /public/waitlists/{id}/signups/{email}/verify
     { "token": "..." }

The GET method is used by the clickable link in the verification email. Both methods return the same JSON response on success:

{
  "verified": true,
  "message": "Email verified successfully"
}

The token comparison uses timing-safe comparison (crypto.timingSafeEqual) to prevent token guessing via timing side-channel attacks.

When require_consent is enabled on a waitlist, the signup form displays an unchecked consent checkbox. Users must check it before they can submit the form.

The signup request must include "consent": true or it will be rejected with 400 Bad Request and the error code VALIDATION_ERROR (with a consent field error in the errors array). When consent is given, the following are stored with the signup record:

Field Description
consent_given_at ISO 8601 timestamp of when consent was given
consent_text_version Version identifier of the consent text shown ("custom" if custom text was set, "v1" for the default)
privacy_policy_version Version of the privacy policy at the time of consent ("v1")

These fields are included in CSV exports. See Creating Waitlists for configuration details.

Closed Waitlist

When a waitlist’s status is set to "closed":

  • The hosted signup page shows “Waitlist Closed” with the message “This waitlist is no longer accepting signups”
  • The embed widget shows a “This waitlist is currently closed” message instead of the form
  • The API rejects new signups with 403 Forbidden and the message “This waitlist is currently closed”

You can close and reopen a waitlist at any time from the dashboard or via the API.

Position Offset (Advanced+)

!
Advanced Plan Required Position offset requires an Advanced plan or higher.

When a position_offset is configured, all position numbers displayed to signups are inflated by that amount. For example, with an offset of 500:

  • The 1st signup sees position 501
  • The 42nd signup sees position 542
  • Total signups displayed is also inflated

This creates the impression of a larger, more established waitlist. Internal positions used for referral ranking are not affected.

Success Page

After signing up, users are redirected to /success.html which shows:

  • Their position on the waitlist (unless hidden by Advanced+ settings)
  • Their unique referral link with a copy button
  • Social sharing buttons (X/Twitter, Facebook, WhatsApp, Instagram)
  • The referral leaderboard showing top referrers
  • Email verification status (if enabled by Pro users — a verification link is sent by email)

The success page reads its data from URL query parameters:

Parameter Description
wl Waitlist ID
email The signup’s email address
pos Position on the waitlist
ref The signup’s referral token
total Total number of signups on the waitlist

If the waitlist owner has configured a custom redirect URL, the user is redirected there instead of /success.html, with the same query parameters appended.

Custom Questions

Custom questions appear on the signup form below the standard fields. Users’ answers are stored with their signup record and included in:

  • CSV exports
  • API responses when listing signups
  • Webhook payloads

Question Types

Type Behavior
Text Free-form text input
Dropdown Select one option from a predefined list
Checkbox Yes/no toggle

Validation

  • Required questions must be answered before the form submits
  • Dropdown answers must match one of the predefined options
  • Text answers are truncated to 1,000 characters

Signup Count

The public count endpoint returns the total number of signups for a waitlist:

GET /public/waitlists/{id}/count

The count returns null when:

  • The waitlist has 10 or fewer signups (to avoid showing low numbers)
  • The waitlist owner has Hide position enabled
!
Advanced Plan Required The Hide position setting requires an Advanced plan or higher.

  • Creating Waitlists — configure fields, custom questions, consent, and all waitlist settings
  • Embed Widget — add a signup form to any website with one line of code
  • Referral System — how viral referral tracking and leaderboards work
  • Error Handling — error codes and response formats for all API endpoints