Skip to content

Migrating to Formward

Formward accepts a standard form POST, so moving a form from another backend usually means changing the URL it posts to and renaming a hidden field or two. This page is the provider-neutral reference. For the exact before-and-after snippet from a specific provider, use its guide:

1. Create the form and copy its endpoint

In the dashboard, create a form and set the notification email. Its endpoint has this shape:

https://forms.formward.eu/f/<formId>

2. Point your form at it

Put the endpoint in the form's action, or in the URL of your fetch() call:

<form action="https://forms.formward.eu/f/<formId>" method="POST">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
  <button type="submit">Send</button>
</form>

Every named field is stored as sent. URL-encoded, multipart and JSON bodies are all accepted. Provider keys such as an access key hidden field are not needed and can be removed.

3. Rename the special fields

Formward reads these hidden fields. Most providers have an equivalent under a different name.

FieldWhat it does
_subjectSubject line of the notification email.
_replyto / _reply_toOverrides the Reply-To address on the notification email. Without it, a field named email is used, so most forms need no extra field. Add _replyto when the email input has another name or the form has several.
_redirectWhere the browser goes after a classic POST. A relative path, or an absolute URL whose origin is in the form's allowed origins; anything else is ignored. Without it, the redirect set on the form applies, then Formward's own thanks page.
_gotchaHoneypot. Hide it from people; if a bot fills it in, the submission is stored as spam, sends no notification and does not count toward your quota.

Details and examples are in special fields.

4. Check how your JavaScript reads the response

Send Accept: application/json and Formward answers with JSON: a 200 with { ok: true, id } on success, and { ok: false, error } with a status code when something is wrong. Code that checks res.ok keeps working. Code that reads a field only your old provider returned, such as an errors array or a message string, needs a small change. The codes you are most likely to meet:

  • 402: the monthly submission limit of your plan is reached.
  • 422: a field failed a validation rule set on the form, or required consent was missing.
  • 429: too many posts from one address in a short time; a Retry-After header says when to try again.
  • 403: the origin is not allowed, the Turnstile check failed, or the form sent files on a plan without uploads.

The full list is in responses and redirects, and a working script is in AJAX submissions.

5. File uploads

Forms that send files need enctype="multipart/form-data" and a plan that includes uploads: Professional and up, with 5 files of up to 10 MiB each on Professional. On a plan without uploads, a post that carries files is rejected with 403. See file uploads.

6. Lock the endpoint to your site

Add your site's origin, for example https://www.example.com, to the form's allowed origins. With the list empty, any origin can post. Once it has entries, a request whose Origin header does not match is refused with 403, and that includes server-side requests that send no Origin at all, so leave the list empty for a form you post to from a server.

Bring your history

Changing the endpoint only affects new submissions. Your old ones stay with your previous provider until you move them. Under Dashboard, Import & migrate:

  • CSV importer. Upload a CSV of past submissions into one of your forms. Any CSV with a header row works, up to 5,000 rows and 10 MB per file. Imported rows send no email and do not count toward your quota. Attachments are not imported, only the cell values.
  • Form importer. Paste your original HTML form (Formspree, Basin, Getform and Web3Forms), a Formspree formspree.json, or a JSON Schema, Typeform, Tally or Google Forms definition. It maps the fields and creates an inactive draft. Notification addresses, webhooks, autoresponders and spam settings are listed for you to review and are never switched on by the import.
  • Formspree endpoint rewriter. Paste a Formspree form URL or ID and pick a Formward form to get the matching endpoint and a drop-in snippet.

The CSV importer keeps each row's original date when the file has a dedicated submission-date column named Submitted At, created_at or createdAt. A column of your own merely called "date" or "time" is kept as an answer and never used as the submission time. Dates in ISO 8601 (2024-04-03T09:30:00Z) are read as written. A slash date like 03/04/2024 could be 3 April or 4 March, so instead of guessing, the importer dates those rows at import time and tells you how many it affected.

Mind retention. Forms on the Free plan keep submissions for 30 days, and any form can have its own retention window. Imported rows whose original date is older than the window are deleted by the nightly retention sweep. The importer tells you how many rows that is, so you can raise the window first.

What does not move

Webhooks, Zapier or Make scenarios, Slack connections, autoresponders, CAPTCHA keys and team members are settings in your old account, not part of the form. Recreate the ones you need in Formward: webhooks (including Slack, Discord, Teams and Mattermost) start on Professional and the autoresponder on Professional. See integrations and webhooks.

Checklist

  1. Create the form in Formward and set the notification email.
  2. Change the form's action or fetch() URL to the Formward endpoint.
  3. Rename subject, redirect and honeypot fields to the names above. A field named email already sets Reply-To.
  4. If your JavaScript reads the response body, check it against the JSON shape above.
  5. Add your site's origin to the form's allowed origins.
  6. Send a test entry, including one with a file if the form takes uploads, and check the dashboard and the email.
  7. Recreate webhooks and autoresponders, then import your history from CSV if you want it.
  8. Once the live form has worked for a few days, switch off the form at your old provider.