Static sites are the easiest sites to love: they’re fast, they cost almost nothing to host, and there’s no server to patch at 2am. The catch is always the same. The moment you need a form — a registration, a booking, a product configurator with a live price — a static site has nowhere to send it.

The usual answer is to bolt on a hosted form endpoint (Formspree, Netlify Forms, Web3Forms). That works until it doesn’t: submission caps, no real validation, no conditional logic, no pricing, and your submission data living on someone else’s infrastructure.

There’s a cleaner option if you already work in WordPress. Build the site visually in Builderius, export it to static files, and let CraftForms — running on a locked-down WordPress backend — handle every form. You get a static frontend on Cloudflare or Netlify Pages and a real form/price engine you own. This article shows the exact wiring, including a one-line shortcode that survives the static export intact.

New here? Two companion articles set the stage: Using WordPress as a Form Backend for Static Sites and Web Apps introduces the mechanism, and Use WordPress as a Locked-Down Form Backend for Static Sites covers securing the backend. This post is the “build it in Builderius” path.


The stack

Three pieces, each doing one job:

  • Builderius — the visual builder. Design pages in WordPress, then use its static-site generator to crawl the rendered pages and export clean HTML/CSS/JS with no WordPress dependency in production. Deploys straight to Netlify, Cloudflare Pages, GitHub Pages, or S3.
  • CraftForms — the form + price engine. Builds forms, validates input, runs conditional logic and price formulas (client-side for instant feedback, re-verified server-side on submit), stores submissions, sends notifications, takes payments.
  • A locked-down WordPress install — invisible to the public, serving only the CraftForms REST endpoints. As of CraftForms 1.6, a single toggle in CraftForms → Settings → Embed (“Headless backend mode”) does this natively — no mu-plugin required. See below for what it covers.

The static site your visitors load has no WordPress in it. When someone opens a form, a tiny script fetches the current form from your backend and boots it in place. When they submit, it posts to your backend. Nothing else touches WordPress.


The problem with freezing a form

Here’s the subtle part most walkthroughs skip.

When a static generator crawls a page that has a form rendered directly into it, it freezes a snapshot of that form. For a CraftForms form rendered inline, that snapshot bakes in two things that don’t survive well:

  1. A submit URL of the …/wp-json/craftforms/v1/submit/… form. On a locked-down backend, /wp-json/ is often blocked outright — so the frozen form posts to a dead URL.
  2. A one-time security nonce. Nonces expire in hours and are tied to a session. On a page frozen at build time and served for weeks, it’s stale on arrival.

You can work around both by hand. But there’s a purpose-built path that avoids the problem entirely: don’t freeze the form — freeze a placeholder that fetches the live form at runtime.


The shortcode

CraftForms ships a shortcode built for exactly this:

[craftforms_static_form key="YOUR_EMBED_KEY"]

Instead of rendering the whole form, it outputs the CraftForms embed placeholder:

<div data-craftforms-embed="YOUR_EMBED_KEY"></div>
<script src="https://your-backend.com/wp-content/plugins/craftforms/build/webcomponents/embed.js" defer></script>

That’s what gets frozen into your static export — two lines, no baked nonce, no dead submit URL. At runtime embed.js decodes your backend’s URL from the embed key, calls GET /craftforms/v1/embed/{key}, and replaces the placeholder with the live form and its current price logic. Because the form is fetched fresh every visit, you can change fields or prices in WordPress without rebuilding the static site.

Link a form to a catalog item for catalog pricing by adding resource-id:

[craftforms_static_form key="YOUR_EMBED_KEY" resource-id="42"]

Step by step

1. Enable external submissions on the form

Open your form → Submission settings → turn on Allow External Submissions. This is what lets a request from your static domain (a different origin) be accepted at all.

2. Create an embed key

Go to CraftForms → Settings → Embed and create a key for that form and the domain your static site will be served from (e.g. camp.example.com). The key encodes your WordPress URL, so you never hard-code it on the static side. Copy it.

3. Drop the shortcode into Builderius

In the Builderius canvas, add a Shortcode module where you want the form and set it to:

[craftforms_static_form key="aHR0cHM6Ly9mb3Jtcy5leGFtcGxlLmNvbQ.abc123"]

Builderius renders the shortcode server-side, so the <div> + <script> land in the page’s HTML — which is exactly what its static-site generator captures.

4. Generate and deploy the static site

Run Builderius’ static-site generation on your published release, then deploy to Cloudflare Pages / Netlify / GitHub Pages. The generator freezes the placeholder verbatim and — because embed.js is served from your WordPress domain — bundles the script into the export automatically.

5. Open the static page

The form appears, live. Change an option and the price updates instantly (computed in the browser). Submit, and it posts to your locked-down backend — which independently re-computes the price and rejects any tampering before storing the submission or charging a card.

Why this is fast: the page was already static and instant, and once the form boots, every option change recalculates the price in the browser with no backend call. The backend is touched exactly once — on submit. There’s no per-click round-trip, so a shopper can configure a product as fast as they can click, on hosting that costs almost nothing.


Why this is safe

External submission endpoints are public by nature, so CraftForms doesn’t trust the client:

  • Origin check — the embed key is bound to one domain; requests from anywhere else are refused.
  • Server-side price re-verification — the browser shows a live price for UX, but the server recomputes _price, stock, and booking capacity from the form’s own formulas and rejects mismatches. A user editing the price in devtools gets a 4xx, not a discount.
  • Locked-down surface — flip Headless backend mode on in CraftForms → Settings → Embed and the plugin restricts the REST API to its own namespace (anonymous requests to anything else get a 403), disables XML-RPC, and blacks out every public frontend request for logged-out visitors — leaving just the CraftForms embed and submit endpoints reachable. It’s PHP-layer, fully reversible, and ships with a CRAFTFORMS_HEADLESS_DISABLE constant for wp-config.php as a kill switch if you ever lock yourself out.

That one toggle covers the protections that matter most day to day. It deliberately stops short of two things a plugin can’t safely do for you: hiding /wp-login.php behind a custom slug, and server-level rules (blocking xmlrpc.php at nginx/Apache, disabling PHP execution in /uploads). If you want those too, the locked-down guide still has the extra mu-plugin snippet and server config for them — otherwise the built-in toggle is now the fastest way to get most of the way there.

One honest caveat: CraftForms does not yet ship a built-in CAPTCHA or honeypot. For public submission endpoints, add a required request header to the form (Submission settings → Required headers) as a lightweight shared-secret filter, and keep an eye on the roadmap for a first-class anti-abuse layer.


Not using Builderius?

The same embed placeholder works anywhere. CraftForms ships copy-paste starters for other static generators:

  • Astro — a <CraftForm embedKey="…" /> component. Find out more on how to add a form to Astro website.
  • Hugo — a {{< craftform key="…" >}} shortcode and a partial.

They’re in examples/static-site/ in the plugin, and each emits the identical <div data-craftforms-embed> + embed.js snippet. One mechanism, every static toolchain.


The payoff

You keep everything static sites are good at — speed, cheap hosting, a tiny attack surface — and you stop pretending forms are someone else’s problem. One WordPress backend, locked down and invisible, powers the forms, pricing, bookings, and payments across every static site you build. And because the form is fetched at runtime, your prices are never one stale deploy behind.

CraftForms embedding, external submissions, the shortcode, and Headless backend mode are CraftForms PRO features.