# Webflow

> Send a Webflow Form Block to Ikiform with a custom action, keep Webflow's success and error states with a short script, and allow your webflow.io staging site.

Webflow's Form Block can post to any URL. Point its action at your Ikiform endpoint and the form keeps the layout and styles you built in the Designer, while Ikiform validates, filters spam, stores, emails and sends webhooks.

## What a custom action changes

- Webflow only processes a form when it is the destination. With a custom action, the browser posts straight to Ikiform, so the submission doesn't appear in Webflow's form submissions and Webflow sends no notification email.
- Webflow's own destinations can't run next to a custom action. Remove them under **Send to** before you add Ikiform.
- Webflow's success and error blocks (`.w-form-done` and `.w-form-fail`) and the form's own redirect setting stop working, because Webflow never sees the result. Visitors land on Ikiform's thank-you page or on your **Redirect after submit** URL. [Step 4](#keep-success-state) brings Webflow's blocks back.

## Set up the form

### Step 1: Point the form at Ikiform

Select the form inside the Form Block and open the **Settings** panel. Under **Send to**, choose a custom action, paste your endpoint into **Action** and set **Method** to **POST**.

`Action`:

```text
https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx
```

Leaving the method as GET makes the browser open the endpoint as a page, which answers `404 not_found`. Ikiform only takes posts.

### Step 2: Name the fields

Each input's **Name** setting becomes the field name in Ikiform. Webflow fills it from the label, so you get names like `Name`, `Email` and `Field 2`. Rename them to the ids you want to see, such as `name`, `email` and `message`.

- If you define [fields](https://ikiform.com/docs/fields.md) on the Ikiform form, the names must match their ids exactly. Ids are lowercase snake_case, so `Email` and `email` are different fields.
- Remove any reCAPTCHA element from the form. Ikiform doesn't verify it, and its `g-recaptcha-response` value would arrive as an extra field. Use Ikiform's [spam check](https://ikiform.com/docs/spam.md#human-check) instead.

### Step 3: Add a honeypot

Add an Input to the form, set its **Name** to `_gotcha`, and hide it with **Display: none** in the Style panel. In **Custom attributes**, add `tabindex` set to `-1` and `autocomplete` set to `off` so keyboards and password managers skip it. On a paid site plan you can paste this into a Code Embed inside the form instead:

`Code Embed`:

```html
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
```

### Step 4: Choose what happens after submit

The simplest option is a thank-you page. Create one in Webflow, publish it, and paste its full URL into **Redirect after submit** in the Ikiform form's settings.

### Keep Webflow's success and error blocks

To stay on the page, post with `fetch` and toggle Webflow's blocks yourself. Paste this under **Page settings** > **Custom code** > **Before </body> tag**, or in the site's footer code to cover every form. It shows Ikiform's error message inside the error block and uses the button's **Waiting text** while sending.

`Before </body> tag`:

```html
<script>
  document.querySelectorAll('form[action^="https://ikiform.com/f/"]').forEach((form) => {
    const wrapper = form.closest(".w-form");
    const done = wrapper?.querySelector(".w-form-done");
    const fail = wrapper?.querySelector(".w-form-fail");
    const button = form.querySelector('[type="submit"]');

    form.addEventListener("submit", async (event) => {
      event.preventDefault();
      const label = button?.value;
      if (button) {
        button.disabled = true;
        button.value = button.dataset.wait || label;
      }
      try {
        const response = await fetch(form.action, {
          method: "POST",
          headers: { Accept: "application/json" },
          body: new FormData(form),
        });
        const result = await response.json();
        if (result.ok) {
          form.style.display = "none";
          if (fail) fail.style.display = "none";
          if (done) done.style.display = "block";
          return;
        }
        const text = fail?.querySelector("div") ?? fail;
        if (text) text.textContent = result.error.message;
        if (fail) fail.style.display = "block";
      } catch {
        if (fail) fail.style.display = "block";
      } finally {
        if (button) {
          button.disabled = false;
          button.value = label;
        }
      }
    });
  });
</script>
```

> Custom code and the Code Embed element need a paid site plan or a Workspace plan, and neither runs in the Designer. Publish to see them work.

The script posts with `fetch`, so a form whose spam check is set to **Ikiform** answers `403 challenge_required` instead of showing the check page. Use the script with the check off, or skip the script and let the browser post normally, which runs the check with no extra code.

## Allowed domains

If you set allowed domains, list every address the form is published to. Subdomains of a listed domain already match.

| Where the form runs | Add to Allowed domains |
| --- | --- |
| Your custom domain | `example.com`, which also covers `www.example.com` |
| Webflow staging | `your-site.webflow.io` |
| The Designer canvas | Nothing. Custom actions and custom code don't run there. |

- Never add `webflow.io` on its own. Every site on that host would match, including other people's.

## Test checklist

1. Publish to your `webflow.io` staging domain. Forms with a custom action only post from the published site.
2. Submit the form and open the form's submissions in Ikiform. The new submission should be listed under received, not spam.
3. Check the field names match what you set in step 2, and that the honeypot isn't listed: names starting with `_` are never stored.
4. Confirm you land on your thank-you page, or see Webflow's success block if you added the script.
5. Publish to your custom domain and submit once more from there.

## Troubleshooting

| What you see | Why | Fix |
| --- | --- | --- |
| `404 not_found` page after submit | **Method** is GET, so the browser opened the endpoint like a link | Set **Method** to **POST** and publish again. |
| Ikiform's thank-you page instead of Webflow's success message | Webflow's success block only runs when Webflow handles the form | Set **Redirect after submit**, or add the script from step 4. |
| Submissions arrive under the spam filter with `origin_mismatch` | The page that posted isn't on the form's allowed domains | Add the host from the table above. With **Reject** chosen, the same posts get `403 origin_not_allowed` instead. |
| `422 validation_failed` listing an Unknown field | A field name such as `Email` or `g-recaptcha-response` isn't in the form's field definition | Rename the input to the field id, or remove the reCAPTCHA element. |
| The script does nothing | You're testing in the Designer, the site has no paid plan, or the action doesn't start with `https://ikiform.com/f/` | Test on the published site and check the **Action** has no spaces. |
| The error block says `Complete the human check, then send the form again.` | The spam check is set to **Ikiform** and the script posts with `fetch` | Turn the check off for this form, or remove the script. |

## Related

- [Site builders](https://ikiform.com/docs/guides/site-builders.md): The embed that works in any builder.
- [HTML forms](https://ikiform.com/docs/html.md): Redirects, reserved fields and the honeypot.
- [Allowed domains](https://ikiform.com/docs/spam.md#allowed-domains): How origins are matched, and what a mismatch does.
- [Errors](https://ikiform.com/docs/errors.md): Every error code, with its cause and fix.
