Forms
Collect form submissions from your static sites with zero backend code.
How It Works
ZeroDeploy provides a built-in form backend for your deployed sites. When a visitor submits a form, ZeroDeploy captures the data, stores it, and optionally sends you an email notification.
- Add a standard HTML form to your site with
action="/_forms/<name>"andmethod="POST" - Deploy your site
- When a visitor submits the form, ZeroDeploy creates the form automatically and stores the submission
- View submissions in the dashboard, CLI, or export as CSV
HTML Markup
Point your form’s action attribute to /_forms/<name>, where <name> is any identifier you choose:
<form action="/_forms/contact" method="POST">
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<label for="message">Message</label>
<textarea id="message" name="message" required></textarea>
<button type="submit">Send</button>
</form>
All form fields are captured as key-value pairs based on the name attribute of each input.
Spam Prevention
Add honeypot fields to catch bots. Any field with a name starting with _hp acts as a trap — if a bot fills it in, the submission is silently rejected with a fake success response.
Basic honeypot — a single hidden field:
<form action="/_forms/contact" method="POST">
<!-- Honeypot: positioned off-screen, invisible to real users -->
<div style="position:absolute;left:-9999px" aria-hidden="true">
<input type="text" name="_hp" tabindex="-1" autocomplete="off">
</div>
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<button type="submit">Subscribe</button>
</form>
Stronger honeypot — use realistic field names that tempt bots to fill them in. Any field starting with _hp works (_hp, _hp_website, _hp_url, etc.):
<form action="/_forms/contact" method="POST">
<!-- Honeypot fields: look real to bots, hidden from users -->
<div style="position:absolute;left:-9999px" aria-hidden="true">
<input type="text" name="_hp_website" tabindex="-1" autocomplete="off">
<input type="text" name="_hp_url" tabindex="-1" autocomplete="off">
</div>
<label for="name">Name</label>
<input type="text" id="name" name="name" required>
<label for="email">Email</label>
<input type="email" id="email" name="email" required>
<button type="submit">Send</button>
</form>
- Use
position: absolute; left: -9999pxinstead ofdisplay: none— some bots detectdisplay: noneand skip those fields - Add
aria-hidden="true"so screen readers ignore the hidden fields - Add
tabindex="-1"andautocomplete="off"to prevent keyboard focus and browser autofill - Use realistic names like
_hp_websiteor_hp_url— bots are more likely to fill fields that look like real inputs
All _hp-prefixed fields are stripped from the submission data and never stored.
Time-Based Detection
ZeroDeploy automatically sets a signed timestamp cookie when serving HTML pages. If a form is submitted less than 3 seconds after the page loads, the submission is silently rejected — the same way honeypot-triggered submissions are handled. This catches headless browsers and scripts that submit forms instantly. No configuration is needed; it works automatically on all forms.
Content Scoring
Every submission is automatically scored using 8 content heuristics (URLs in name fields, excessive links, HTML tags, spam keywords, mixed character scripts, all-caps content, suspicious user agents, and IP frequency). Submissions scoring above the spam threshold are silently rejected. Suspected spam (moderate scores) is stored but flagged — you can review it in the dashboard under the “Suspected Spam” tab.
Success & Error Handling
After submission, visitors are redirected back to the form page with a query parameter indicating the result:
| Query Parameter | Meaning |
|---|---|
?success=true | Submission was accepted |
?error=rate_limit | Too many submissions (rate limited) |
?error=limit_reached | Monthly submission limit reached |
?error=spam | Honeypot triggered |
?error=invalid | Invalid form data |
Use these parameters to show feedback messages:
<script>
const params = new URLSearchParams(window.location.search);
if (params.get('success') === 'true') {
document.getElementById('form-message').textContent = 'Thanks! We\'ll be in touch.';
}
if (params.get('error')) {
document.getElementById('form-message').textContent = 'Something went wrong. Please try again.';
}
</script>
<p id="form-message"></p>
Email Notifications
Get notified by email whenever a form receives a new submission:
# Enable notifications
zerodeploy form notify contact --email me@example.com
# Disable notifications
zerodeploy form notify contact --disable
You can also configure notifications from the dashboard under your site’s Forms tab.
Viewing Submissions
Via Dashboard
Navigate to your site in the dashboard and click the “Forms” tab to see all forms and their submissions.
Via CLI
# List all forms for a site
zerodeploy form list
# View recent submissions
zerodeploy form submissions contact
# Export as CSV
zerodeploy form export contact
Via API
# List forms
curl -H "Authorization: Bearer $TOKEN" \
"https://api.zerodeploy.dev/sites/my-site/forms"
# Get submissions
curl -H "Authorization: Bearer $TOKEN" \
"https://api.zerodeploy.dev/sites/my-site/forms/contact/submissions"
# Export CSV
curl -H "Authorization: Bearer $TOKEN" \
"https://api.zerodeploy.dev/sites/my-site/forms/contact/export"
Deleting Forms
Delete a form and all its submissions:
zerodeploy form delete contact
Rate Limiting
Form submissions are rate limited at multiple levels to prevent abuse:
- 10 submissions per minute per IP address per site (with progressive throttling after 5)
- 100 submissions per hour per site on the Starter plan (500/hr on Pro)
- Duplicate detection — identical submissions from the same site are silently rejected within a 1-hour window
If a visitor exceeds the limit, they are redirected with ?error=rate_limit.
Plan Limits
| Feature | Starter | Pro |
|---|---|---|
| Submissions per month | 100 | 1,000 |
| Email notifications | Per form | Per form |
| CSV export | Unlimited | Unlimited |