Skip to content
UseWait Docs
Esc
navigateopen⌘Jpreview
On this page

Page code

The contract for a waitlist page's reactCode, for hand-written or agent-generated pages.

A waitlist page is a single JavaScript function rendered in a sandbox with React in scope. You can replace the default template by setting reactCode on create or update, over the REST API or MCP.

The contract

  • One plain function declaration named GeneratedWaitlist:

    function GeneratedWaitlist(props) {
      // ...
    }
  • No JSX, no imports, no TypeScript. Use React.createElement and hooks through the global React (React.useState, React.useEffect, …). Use var and function () {}; avoid const, let, and arrow functions.

  • Style with inline style objects. The page renders full viewport; own the whole background.

  • props.waitlistData contains the waitlist’s name and description.

Submitting signups

Call props.onSubmit from your form handler:

props.onSubmit({ email: email, name: name || undefined });

Results arrive as window messages. Listen for event.data.type === "waitlist-result":

React.useEffect(function () {
  var handler = function (event) {
    if (event.data && event.data.type === "waitlist-result") {
      if (event.data.success) {
        // event.data: { position, alreadyJoined?, referralEnabled?,
        //   referralCode?, referralCount?, referralBoost?, referralMessage? }
      } else {
        // event.data.error holds the message
      }
    }
  };
  window.addEventListener("message", handler);
  return function () {
    window.removeEventListener("message", handler);
  };
}, []);

Embeds and the content security policy

Waitlist pages run under a strict Content-Security-Policy, because every page is served from the shared usewait.com origin. What that means for your page code:

  • Allowed: inline styles and scripts (your reactCode), images from any https URL, and iframes from a fixed allowlist of embed hosts — YouTube, Vimeo and Calendly. Frame the plain embed URL directly, for example:
    • https://www.youtube.com/embed/<id> (or https://www.youtube-nocookie.com/embed/<id>)
    • https://player.vimeo.com/video/<id>
    • https://calendly.com/<user>/<event>
  • Blocked: third-party <script> tags (including widget loaders like Calendly’s widget.js — use the iframe embed instead), fetch/XHR to any external host, and forms that submit off-site (form-action is locked to UseWait). Signups go through props.onSubmit, not a form action.

If you need a video or a booking widget, drop in the iframe. Anything that needs an external script or posts data to another service will be blocked by the browser.

Turnstile

When props.turnstileEnabled is true the page must render the Cloudflare Turnstile widget. The server rejects any signup without a token, so a form that only prints a “complete the verification” message never submits.

var _t = React.useState(null);
var turnstileToken = _t[0], setTurnstileToken = _t[1];
var turnstileRef = React.useRef(null);

React.useEffect(function () {
  if (!props.turnstileEnabled || !props.turnstileSiteKey) return;
  if (!document.getElementById("turnstile-script")) {
    var sc = document.createElement("script");
    sc.id = "turnstile-script";
    sc.src = "https://challenges.cloudflare.com/turnstile/v0/api.js";
    sc.async = true;
    document.head.appendChild(sc);
  }
  var render = function () {
    if (window.turnstile && turnstileRef.current && !turnstileRef.current.hasChildNodes()) {
      window.turnstile.render(turnstileRef.current, {
        sitekey: props.turnstileSiteKey,
        callback: function (t) { setTurnstileToken(t); },
        "expired-callback": function () { setTurnstileToken(null); },
        theme: "auto"
      });
    }
  };
  if (window.turnstile) { render(); }
  else {
    var i = setInterval(function () {
      if (window.turnstile) { clearInterval(i); render(); }
    }, 100);
    return function () { clearInterval(i); };
  }
}, [props.turnstileEnabled, props.turnstileSiteKey]);

Mount the container inside the form, before the submit button, block submit while the token is missing, and pass it to onSubmit:

props.turnstileEnabled && props.turnstileSiteKey
  ? React.createElement("div", { ref: turnstileRef })
  : null

On a custom domain Turnstile is off and props.isCustomDomain is true. Render a hidden honeypot input instead and pass its value as honeypot.

Branding

Free waitlists show a “Made with UseWait” badge. UseWait renders it outside your page code, so do not add your own and do not cover it. It disappears once the waitlist is licensed.

When referrals are enabled, build the subscriber’s share link from the referral code in the result payload:

var link =
  window.location.origin + window.location.pathname + "?ref=" + referralCode;

Create without reactCode

The waitlist starts on the default template, which is a complete working example.

Fetch the current code

GET /api/v1/waitlists/{idOrSlug} (or the get_waitlist MCP tool) returns the live reactCode.

Iterate

Modify or regenerate the code and PATCH it back. The hosted page updates immediately.

Was this page helpful?