Static sites are fast and cheap to host. The usual snag is the contact form: there is no server to receive POST, no PHP mailer, and no Node process to call an email API. This guide shows how to add a contact form to a static website without a backend, using a form API endpoint, so GitHub Pages, Netlify, Cloudflare Pages, and Vercel all work the same way.
If you want leads on WhatsApp as well as email, the same form endpoint can deliver both. Start with the HTML path below; WhatsApp unlocks on higher FormsReach plans when you need it.
What you’ll need
- A static site (HTML, Astro, Hugo, Jekyll, 11ty, or any builder that exports static files)
- Ability to edit the form markup (or paste an HTML block)
- A free FormsReach API key
No VPS, no mailto:, no “serverless function just for one form.”
Why static forms break (and what not to do)
| Approach | Problem |
|---|---|
mailto: |
Opens the visitor’s mail client; often blocked; no spam filter |
| Client-only JS to your Gmail | Exposes credentials or hits CORS / spam walls |
| Serverless function per form | Works, but you own deploy, secrets, retries, and spam |
| Host-only form product | Locks you to that host when you move the site |
A form API is a shared endpoint: the browser posts field data to https://api.formsreach.com/submit with your api_key. The service stores the submission, filters spam, and notifies you. Your site stays static.
For the broader “form to WhatsApp without a backend” story, see the pillar guide: How to send website form submissions to WhatsApp.
Step 1: Add the HTML form
Point any standard form at the FormsReach endpoint and include a hidden API key. Use familiar field names (name, email, message) so notifications stay readable.
<form action="https://api.formsreach.com/submit" method="POST">
<input type="hidden" name="api_key" value="YOUR_API_KEY" />
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message" required></textarea>
<button type="submit">Submit Form</button>
</form>
Replace YOUR_API_KEY with the key from the dashboard. Keep method="POST". Do not put the key in a public git repo if the repo is open source without a build-time inject; for most marketing sites the key is restricted by domain allowlist in the product settings.
Full multi-framework snippets (including JS auto-bind) live in the interactive block on the homepage and on this post when you enable code tabs in the layout. The HTML path above is enough for pure static pages.
Step 2: Deploy like any other HTML file
Because the form posts to an external API, hosting is boring in a good way:
- GitHub Pages / Cloudflare Pages / Netlify / Vercel: commit the form markup, deploy the static output.
- No adapter required: you do not need SSR for the form to work.
- Thank-you page: set a redirect URL in FormsReach (or a static
/thanks/page) so the browser leaves the form after success.
Test on production HTTPS. Mixed content can block posts from an https page to a non-HTTPS endpoint; FormsReach is HTTPS-only.
Step 3: Get notified (email first, WhatsApp when ready)
On Free and Starter, FormsReach meters email notifications (and free webhooks / workflow rules) from a monthly credit pool. Free includes 500 credits per month. A typical path is 1 credit for the accepted submission plus 1 credit for the email notification.
WhatsApp via the official Meta WhatsApp Business API is available on Pro and Agency, also from the same credit pool. You do not need WhatsApp to validate the static form setup. Turn it on when your team lives in chat instead of inbox.
Optional: attach a webhook (0 credits) to push JSON into Sheets, Slack, or your own URL without writing a server on the marketing site.
Step 4: Smoke-test before you ship
- Submit the form with a real email you control.
- Confirm the submission appears in the FormsReach dashboard.
- Confirm the notification arrives (email or WhatsApp).
- Try an empty required field and a throwaway spam-like message; honeypot and server-side filters should drop junk without a CAPTCHA on the page.
Troubleshooting
Form reloads but nothing arrives
Check the browser Network tab: the request should hit api.formsreach.com with status success. A 4xx often means a bad or missing api_key, or domain restrictions.
Works locally, fails on the host
Confirm the live HTML still contains the hidden api_key (some minifiers or CMS blocks strip hidden inputs). Confirm the form action was not rewritten by the host.
CORS errors
Classic form POST navigations do not need CORS the way fetch does. If you switched to fetch/FormsReach.init, use the official JS SDK pattern and HTTPS.
I only want SPA behavior
Use @formsreach/js with data-formsreach on the form, or the React package if the static site is really a React export. See React contact form without a backend, or the homepage code tabs for the JS snippet.
I need Astro-native markup
Same endpoint and hidden field work inside a .astro component with zero client JS. Prefer that when you want zero hydration.
Choose a form API over another backend for static sites
Static hosting wins on speed and cost. A form API keeps that win: one action URL, spam filtering, email on free tiers, and optional WhatsApp when sales needs it. FormsReach is built for that path: no PHP, no server of your own, Free with 500 credits/month, webhooks included, WhatsApp on Pro and Agency via Meta’s Business API.
