Do I need a server or a build step?
No. The form is plain HTML posting to a hosted URL, so it works on any static host. A JavaScript submission is supported but never required.
A static host will serve your HTML but it will not accept a POST. SubmitHarbor gives the form somewhere to go: one endpoint that validates the fields, drops obvious bots, and keeps every submission in a private inbox you can read, search, and export.
This is ordinary HTML. No build step, no client library, no JavaScript needed — it works the same on Netlify, GitHub Pages, Cloudflare Pages, S3, or a folder served by nginx.
<form action="https://www.submitharbor.com/api/submit/sh_your_project_key" method="POST">
<label>
Your email
<input type="email" name="email" required />
</label>
<label>
Message
<textarea name="message" required></textarea>
</label>
<!-- Bots fill this in. People never see it. -->
<input type="text" name="website" tabindex="-1" autocomplete="off" hidden />
<button type="submit">Send</button>
</form>Swap the key in the action for your own and the form is live. A native form post sends application/x-www-form-urlencoded; a fetch call can send JSON instead. The endpoint reads both.
There is nothing to install and nothing to sign up for first. The demo key below is the same route the product uses.
curl -i -X POST https://www.submitharbor.com/api/submit/demo_contact_7x2p \
-H "Content-Type: application/json" \
-d '{"email":"you@example.com","message":"Testing the demo endpoint."}'The shared demo key validates a submission and echoes it back, then discards it. It never writes to the database, because a stored demo submission would leave a stranger's details in an inbox nobody owns. Create your own endpoint to keep what arrives.
Validation happens on the server, so it still applies when someone posts around your page. Every rejection comes back as a plain sentence you can show the visitor.
| Field | Rule |
|---|---|
| Required. Must contain a name, an @, and a dotted domain. | |
| message | Required. At least 3 characters after trimming. |
| Any other field | Optional. Stored as sent, trimmed, up to 5,000 characters. |
| website, _gotcha | Honeypots. If either is filled the submission is accepted and discarded. |
| _redirect | Optional. A URL on the submitting origin or the allow-list to return the browser to. |
No puzzle, no third-party widget, no tracking script. Three server-side controls do the work.
website input. People never see it, so they never fill it. When it arrives populated the endpoint answers 200 and quietly discards the submission, which keeps a bot from learning it was caught.Every stored submission lands in a private inbox scoped to the endpoint that received it and the account that created it.
Worth reading before you build on it. These limits apply today.
No. The form is plain HTML posting to a hosted URL, so it works on any static host. A JavaScript submission is supported but never required.
To the endpoint, then to the private inbox for that project. Nothing is stored on your host, so a static deploy stays static.
Yes. The shared demo key accepts submissions and shows you the validated payload. It does not store anything, so create your own endpoint once you want to keep what arrives.