Skip to content
← All migration guides

Migrate · Web3Forms

Migrate from Web3Forms to Formward

Web3Forms posts every form to one URL, https://api.web3forms.com/submit, and tells forms apart with an access_key hidden field. On Formward the form ID is part of the endpoint, so the access key goes and the action changes.

The special fields map closely: subject and redirect become _subject and _redirect, and the botcheck honeypot becomes _gotcha. Like Web3Forms, Formward uses a field named email as the Reply-To address by default; replyto becomes _replyto if you use it to override that. Web3Forms' FAQ says it does not store submissions; Formward keeps each one in the dashboard as well as emailing it.

Last checked 7 October 2026. What this guide says about Web3Forms comes from Web3Forms's own documentation, listed under Sources. Check their current docs if something looks different in your account. The Formward side is the reference in the migration docs.

The change

Change the action, delete the access_key input, and add underscores to subject and redirect (and to replyto, if you use it).

Before: Web3Forms, HTML

<form action="https://api.web3forms.com/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY">
  <input type="hidden" name="subject" value="New enquiry">
  <input type="hidden" name="redirect" value="https://example.com/thanks">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <input type="checkbox" name="botcheck" class="hidden" style="display: none;">
  <button type="submit">Send</button>
</form>

After: Formward, HTML

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

Before: Web3Forms, fetch()

const res = await fetch("https://api.web3forms.com/submit", {
  method: "POST",
  headers: { "Content-Type": "application/json", Accept: "application/json" },
  body: JSON.stringify({ ...Object.fromEntries(new FormData(form)), access_key: "YOUR_ACCESS_KEY" }),
});
const json = await res.json();
if (!json.success) throw new Error(json.message);

After: Formward, fetch()

const res = await fetch("https://forms.formward.eu/f/<formId>", {
  method: "POST",
  headers: { Accept: "application/json" },
  body: new FormData(form),
});
const data = await res.json();
if (!data.ok) throw new Error(data.error);

Field and feature mapping

Web3FormsFormwardNotes
https://api.web3forms.com/submithttps://forms.formward.eu/f/<formId>The form ID is in the URL.
access_keyremoveNot needed. Lock the endpoint to your site with allowed origins instead.
subject_subjectSubject of the notification email.
replyto (defaults to email)email, or _replytoFormward falls back to the email field too. Use _replyto only to override it with a different address.
redirect_redirectFormward also accepts a relative path; an absolute URL must be on an allowed origin.
from_nameForm settingsCustom sender branding is on Business.
ccemailExtra notification recipientsFrom Personal.
botcheck_gotchaA hidden text input; any value in it marks the submission as spam.
h-captcha-response, recaptcha_responsecf-turnstile-responseFormward supports Cloudflare Turnstile, optional per form.
attachmentfile input, multipartUploads are on Professional and up (5 files of up to 10 MiB each on Professional).

What changes, what stays

Changes

  • The action or fetch() URL, and the access_key field goes.
  • subject and redirect gain a leading underscore, and so does replyto if you use it; botcheck becomes _gotcha.
  • JavaScript reads data.ok and data.error instead of json.success and json.message.

Stays the same

  • The email field, which sets Reply-To by default.
  • Your other field names; every named field is stored as sent.
  • JSON or FormData bodies with Accept: application/json.
  • multipart/form-data for forms with files.

Differences to test before you switch

Specific to Web3Forms

  • Web3Forms uses the email field as the reply-to address by default, and so does Formward. Where you set replyto to override it, use _replyto (or _reply_to).
  • Web3Forms' redirect field needs an absolute https URL, on the same domain on its free plan, and is ignored for JavaScript submits. Formward's _redirect takes a relative path or a URL on an allowed origin, and is also ignored for JSON requests.
  • Web3Forms' troubleshooting page says server-side calls need a paid plan and IP allowlisting. Formward accepts server-side posts on any plan as long as the form's allowed origins list is empty.

How Formward behaves

  • JSON responses. Send Accept: application/json and a success is a 200 with { ok: true, id }. An error is { ok: false, error } with a status code. Without that header, a successful post redirects or shows Formward's thanks page. Code that only checks res.ok keeps working.
  • Status codes. 402 when the plan's monthly submission limit is reached (the body has upgrade: true), 422 when a field fails a validation rule set on the form or required consent is missing, 429 when one address posts too often (with a Retry-After header), and 403 when the origin is not allowed, the Turnstile check fails or files are sent on a plan without uploads.
  • File uploads. Uploads need enctype="multipart/form-data" and a plan that includes them: Professional and up (5 files of up to 10 MiB each on Professional). On Free and Personal a post that carries files is refused with 403, so test an upload before you switch a form that takes attachments.
  • Redirects. A hidden _redirect is followed only if it is a relative path or a URL on one of the form's allowed origins; otherwise it is ignored and the redirect set on the form applies, then Formward's thanks page. JSON (AJAX) requests are never redirected.
  • Spam. If the _gotcha honeypot is filled in, the sender gets a normal success response, but the submission is stored as spam, sends no notification and does not count toward your quota. Rate limits apply on every plan; Cloudflare Turnstile and disposable-email blocking are optional per form.
  • Allowed origins. With the list empty, any site can post to the endpoint. Once you add an origin, requests whose Origin header does not match are refused with 403, including server-side requests that send no Origin header.
  • Reply-To. The Reply-To of the notification email is taken from _replyto, then _reply_to, then a field named email. So a plain email field sets Reply-To with no rename, and _replyto only overrides it, for example when the email field has another name or the form has several. An invalid address is dropped, and the email then has no Reply-To.

Every status code and body is listed in responses and redirects.

History, integrations and settings

  • Web3Forms' FAQ says it does not store form submissions, so past entries usually exist only as notification emails in your inbox. If you do have them as a CSV, for example from its Pro submissions API, Formward's importer takes any CSV with a header row.
  • Forms on the Free plan keep submissions for 30 days, and the nightly retention sweep deletes imported rows older than a form's retention window. To keep a longer history, import into a form on a paid plan with a long enough window.
  • The form importer on the same page reads your original Web3Forms HTML form (the access key is dropped) and creates an inactive draft with the fields mapped. Notification addresses, webhooks, autoresponders and spam settings are listed for you to review and are never switched on by the import.
  • Webhooks, Slack, Discord, Telegram and Google Sheets integrations and the autoresponder belong to your Web3Forms account and do not move with the endpoint. Recreate the ones you need: Formward webhooks (including Slack, Discord, Teams and Mattermost), Google Sheets and Baserow sync start on Professional, the autoresponder on Professional, and extra notification recipients on Personal.

Pricing and data location

  • We did not record Web3Forms' prices for this guide; check its pricing page for current plans.
  • Web3Forms states that its servers are in the US-East region and that it is not based in Europe.
  • Formward is priced in euros: Free with 50 submissions a month, then Personal at EUR 15, Professional at EUR 30 and Business at EUR 90 a month (EUR 10, 20 and 60 billed yearly).
  • Formward stores and processes submissions at Hostup AB in Sweden and sends notification email through Mailjet in the EU. The one optional non-EU sub-processor is Cloudflare Turnstile, on forms where you switch it on.

The full side-by-side, with sources, is in Formward vs Web3Forms. Formward's prices are on the plans page, and where each part of Formward runs is on EU data residency.

Step-by-step checklist

  1. Create the form. In the Formward dashboard, create a form, set the notification email and copy the endpoint.
  2. Change the action. Replace https://api.web3forms.com/submit with the Formward endpoint and delete the access_key input.
  3. Rename the special fields. subject becomes _subject, redirect becomes _redirect, replyto becomes _replyto if you use it (a field named email sets Reply-To on its own), and the botcheck checkbox becomes a hidden _gotcha text input.
  4. Restrict origins. Add your site's origin, for example https://www.example.com, to the form's allowed origins. Leave the list empty if you also post from a server.
  5. Test before you switch. Point a copy of the form at Formward and send a few entries: a normal one, one with the honeypot filled, and one with a file if the form takes uploads. Check the dashboard and the notification email.
  6. Recreate integrations. Set up webhooks, Slack or Discord, Sheets sync and the autoresponder on the Formward form.
  7. Retire the Web3Forms form. Switch the live form, watch the first real submissions arrive, then disable the form at Web3Forms so nothing is split between two inboxes.

Sources

Last checked 7 October 2026

Move one form first

The free plan takes 50 submissions a month with no card. Point a copy of one form at Formward, send a few test entries, and switch the live form once the path works end to end.

Migrate from Web3Forms to Formward