← Blog

Collect signups from Cloudflare Pages

Add a signup or waitlist form to a Cloudflare Pages site — no Pages Functions backend, exact domain allow-list, path-style endpoint optional.

Cloudflare Pages is excellent at shipping static marketing sites, docs, and launch pages. What it does not give you out of the box is a durable place for email signups. The HTML still needs an HTTPS endpoint that stores the address, rejects junk, and lets you export later.

Yes — a Cloudflare Pages site can collect signups without Pages Functions by posting its HTML form to a hosted endpoint. The minimum setup is a public campaign id, exact domain allow-list entries for your Pages hosts, and the usual honeypot and spam guardrails.

Pages is static; forms need an endpoint

A Pages deployment is files at the edge. Relative form actions that expect PHP, a home-grown API route, or a same-origin backend fail unless you add that backend yourself. You still want something that accepts POST, checks the caller, and keeps the list somewhere you control.

Common options on the Cloudflare stack

  • Pages Functions + storage you operate. Full control, and you also own rate limits, bot checks, domain policy, exports, and double opt-in if you need them.
  • A general form SaaS embed. Fast until branding, data ownership, or anti-abuse settings fight your stack.
  • Simple Signups. A campaign-scoped subscribe API that already lives on Cloudflare Workers. Your Pages site stays static; the form posts to the Simple Signups origin. That is intake, not a substitute for arbitrary Pages Functions backends.

Allow-list every hostname you embed on

Each campaign stores an exact list of allowed hostnames. On subscribe, the Worker checks browser Origin (or Referer) against that list. Matching is exact after normalization — no *.pages.dev wildcards, and apex does not automatically include www.

Typical Cloudflare Pages entries:

  • Production custom domain — e.g. www.example.com and, if you serve it bare, example.com
  • Project Pages hostname — e.g. my-site.pages.dev if people still hit the default URL
  • Preview deployments — each preview uses its own host (often a unique subdomain under pages.dev). Add the hosts you actually test from; there is no blanket preview wildcard

Empty allow-lists deny third-party embeds. First-party traffic on the Simple Signups product host is handled separately so on-product forms work without listing the product domain on every campaign. Cross-site embeds from your Pages project always need an explicit entry.

Drop-in HTML (direct POST to Simple Signups)

The default path is simple: host the form on Pages, set action to the Simple Signups subscribe URL, include your public campaign id. No Pages Function required for the happy path.

HTML form on Cloudflare Pages
<form action="https://simple-signups.com/api/subscribe" method="POST">
<input type="hidden" name="campaignId" value="pub_your_campaign_id" />
<input type="email" name="email" required placeholder="you@example.com" />
<input type="text" name="hp" tabindex="-1" autocomplete="off"
style="position:absolute;left:-9999px" aria-hidden="true" />
<button type="submit">Subscribe</button>
</form>

Prefer the campaign id in the path? Use the path-style endpoint so the body only needs email (and the honeypot):

HTML form (path-style /c/:id)
<form action="https://simple-signups.com/c/pub_your_campaign_id" method="POST">
<input type="email" name="email" required placeholder="you@example.com" />
<input type="text" name="hp" tabindex="-1" autocomplete="off"
style="position:absolute;left:-9999px" aria-hidden="true" />
<button type="submit">Subscribe</button>
</form>

What this does not replace

Simple Signups is the signup intake layer — domain gate, spam controls, storage, export. It is not a general replacement for Pages Functions, Workers for Platforms, or custom APIs you already run on Cloudflare. Keep those for app logic; point the marketing form at a dedicated campaign.

Related reading