Form Submissions

The platform provides a built-in form submission endpoint so you can collect data from your static site without a third-party service. Submissions are stored in the dashboard and can optionally trigger webhooks.

How It Works

  1. Your HTML form POSTs to /app/forms/submit
  2. The platform parses the data and redirects to a bot-protection challenge (Cap.js)
  3. After verification, the submission is stored and the user sees a thank-you page
  4. Site owners receive an email notification (sandbox submissions are excluded)

Basic Form

Create a standard HTML form with action="/app/forms/submit" and method="POST":

<form action="/app/forms/submit" method="POST">
  <label for="full_name">Full Name</label>
  <input type="text" id="full_name" name="full_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"></textarea>

  <button type="submit">Send</button>
</form>

Each form field's name attribute becomes a column in the submissions table. Use descriptive names — they're displayed as column headers in the dashboard.

Config Fields

Fields with names starting with _ are treated as config (not displayed as submitted data). Use hidden inputs to control form behavior:

<input type="hidden" name="_name" value="contact">
<input type="hidden" name="_return_url" value="https://example.com/thank-you">

Available config fields:

  • _name — Identifies the form. Submissions are grouped by name in the dashboard. Required if using the registration workflow.
  • _return_url — Where the "Return" button on the thank-you page links to. Defaults to /.
  • _sandbox — Set to any value to mark the submission as a test. Sandbox submissions are filtered separately in the dashboard.

Field Name Ordering

Field names can include a numeric sorting prefix separated by a hyphen. The prefix is stripped before storage:

<!-- Stored as "full_name", "email", "message" — but rendered in this order -->
<input name="01-full_name" ...>
<input name="02-email" ...>
<input name="03-message" ...>

This is useful when you want to control column order in the dashboard table.

Multi-Value Fields

If a field name appears multiple times (e.g., checkboxes), all values are stored as an array:

<input type="checkbox" name="interests" value="Sports"> Sports
<input type="checkbox" name="interests" value="Music"> Music
<input type="checkbox" name="interests" value="Art"> Art

Single-value fields are stored as plain strings.

Sandbox / Test Detection

Submissions are automatically marked as sandbox (test) if any of these are true:

  • The query string includes ?sandbox=on
  • The _sandbox config field is set
  • Any field value contains the string testtesttest

Sandbox submissions appear in the dashboard but are filtered into the "Sandbox" environment. They do not trigger notification emails.

Bot Protection

All submissions pass through a Cap.js challenge before being stored. This is handled automatically — no additional markup is needed in your form. The challenge page preserves your original form data and resubmits it after verification.

Notification Emails

Non-sandbox submissions queue an email notification to the site's contact address (configured in _config.yml as contact, or the platform default). Notifications are batched and sent every 3 hours, grouped by site.

Complete Example

<form action="/app/forms/submit" method="POST">
  <input type="hidden" name="_name" value="contact">
  <input type="hidden" name="_return_url" value="/thank-you/">

  <div>
    <label for="full_name">Full Name</label>
    <input type="text" id="full_name" name="01-full_name" required>
  </div>

  <div>
    <label for="email">Email Address</label>
    <input type="email" id="email" name="02-email" required>
  </div>

  <div>
    <label for="phone">Phone</label>
    <input type="tel" id="phone" name="03-phone">
  </div>

  <div>
    <label for="message">Message</label>
    <textarea id="message" name="04-message" rows="4"></textarea>
  </div>

  <button type="submit">Submit</button>
</form>

Testing

During development, add ?sandbox=on to the form's action URL or include testtesttest in a field value to avoid triggering notification emails:

<form action="/app/forms/submit?sandbox=on" method="POST">
  ...
</form>