# Limite de Netlify Forms : ce qui se passe à 100 soumissions, et comment en sortir

> Les anciennes offres Netlify comptent les soumissions de formulaire par site et vous font passer automatiquement au niveau supérieur, et les offres à crédits peuvent mettre le site en pause, alors déplacez le formulaire vers un backend.

Publié le 2026-10-25 · https://ikiform.com/fr/guides/website-builder-forms/netlify-forms-limit

Sur les anciennes offres de Netlify, chaque site inclut 100 soumissions de formulaire par mois, et les dépasser fait passer automatiquement le site à un niveau Forms payant. Sur les offres à crédits des comptes créés depuis septembre 2025, les formulaires sont gratuits, mais une équipe gratuite à court de crédits voit tous ses sites mis en pause, formulaires compris. Déplacer le formulaire vers Ikiform consiste à retirer les attributs Netlify et à définir l'`action`, en HTML simple ou dans n'importe quel framework.

## Ce qui change sur Netlify

Netlify n'est pas un créateur de sites ; c'est un hébergeur avec des formulaires intégrés. Cela détermine à la fois la limite et la façon d'en sortir. La limite qui s'applique dépend de la date de création de votre compte :

| Compte | Ce que dit la documentation de Netlify | Ce que cela signifie pour un formulaire très sollicité |
| --- | --- | --- |
| Anciennes offres, créées avant le 4 septembre 2025 | Forms Level 0 inclut 100 soumissions et 10 Mo d'envois de fichiers par site et par mois. Le dépasser fait passer le site à Forms Level 1, avec 1 000 soumissions, facturé en fin de cycle de facturation. Au-delà, des forfaits d'utilisation supplémentaires ajoutent 500 soumissions à la fois | Une vague de spam peut faire passer un site à un niveau payant sans que personne ne l'ait décidé. Sur l'ancien niveau gratuit, atteindre une limite met en pause tous les sites du compte |
| Offres à crédits, créées depuis | Les soumissions de formulaire sont gratuites et illimitées, sans niveaux | Le formulaire lui-même ne coûte rien. Mais quand une équipe gratuite épuise ses crédits mensuels, Netlify met en pause tous ses projets, et les projets en pause ne reçoivent pas de soumissions de formulaire |

La documentation de Netlify indique clairement que le passage au niveau supérieur sur les anciennes offres est automatique et que vous ne pouvez pas redescendre tant que l'utilisation dépasse le niveau inférieur. Vérifiez le type d'offre de votre équipe et l'utilisation des formulaires du site dans le tableau de bord Netlify avant de décider quoi que ce soit.

La seconde raison de migrer n'a rien à voir avec les chiffres. Netlify Forms fonctionne en lisant votre HTML déployé :

- Les formulaires sont détectés au déploiement. Un formulaire rendu par React, Vue ou Svelte n'existe pas dans ce HTML, donc vous gardez une copie statique masquée que le build peut trouver, et vous y envoyez avec un champ `form-name`.
- Avec Next.js, l'adaptateur OpenNext a besoin de cette copie sous forme de fichier statique dans `public/`, et l'envoi doit aller vers ce fichier statique, pas vers une page Next.js. Le build échoue si `data-netlify` apparaît dans le code React sans cette copie.
- Les soumissions doivent être en urlencoded ou multipart. Le JSON n'est pas accepté.
- Le formulaire ne fonctionne que tant que le site est déployé sur Netlify. Changer d'hébergeur implique de déplacer les formulaires.

Schéma : Comment l'utilisation des formulaires d'un site Netlify sur une ancienne offre grimpe en un mois, et ce que change l'envoi vers Ikiform

1. Sur une ancienne offre, un site commence le mois au Forms Level 0 avec 100 soumissions incluses.
2. La soumission 101 arrive. La documentation de Netlify sur l'utilisation décrit l'utilisation du site, donc une rafale de spam peut suffire à le faire dépasser.
3. Netlify fait passer le site à Forms Level 1, avec 1 000 soumissions, et le facture en fin de cycle.
4. Au-delà du Level 1, des forfaits d'utilisation supplémentaires ajoutent 500 soumissions à la fois.
5. Avec le formulaire qui envoie vers Ikiform, la page reste sur Netlify mais l'envoi part vers l'endpoint Ikiform.
6. Netlify Forms ne reçoit jamais l'envoi, donc il n'a rien à compter ni à faire passer au niveau supérieur.

L'hébergement reste sur Netlify. Seule la destination du formulaire change, et avec elle le comptage.

## Déplacer le formulaire, stack par stack

Avant de modifier le moindre code, créez un formulaire Ikiform par nom de formulaire Netlify et réglez son **Honeypot field** sur `bot-field`. Votre input masqué existant continue alors de servir de honeypot, sans renommage. Choisissez votre stack :

**HTML**

Le HTML simple sur Netlify demande le moins de changements. Supprimez les attributs Netlify et l'input `form-name`, faites pointer `action` vers l'endpoint, et déplacez le chemin de remerciement dans `_redirect` sous forme d'URL complète. L'input `bot-field` reste votre honeypot.

**Avant** (`contact.html`)

```html
<form name="contact" method="POST" action="/thanks" data-netlify="true" netlify-honeypot="bot-field">
  <input type="hidden" name="form-name" value="contact" />
  <p hidden><input name="bot-field" /></p>
  <label>Email <input type="email" name="email" required /></label>
  <label>Topic
    <select name="topic">
      <option value="question">A question</option>
      <option value="bug">Something is broken</option>
      <option value="work">Working together</option>
    </select>
  </label>
  <label>Message <textarea name="message" required></textarea></label>
  <button type="submit">Send</button>
</form>
```

**Après** (`contact.html`)

```html
<form method="post" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx">
  <input name="bot-field" type="text" tabindex="-1" autocomplete="off" hidden />
  <label>Email <input type="email" name="email" required /></label>
  <label>Topic
    <select name="topic">
      <option value="question">A question</option>
      <option value="bug">Something is broken</option>
      <option value="work">Working together</option>
    </select>
  </label>
  <label>Message <textarea name="message" required></textarea></label>
  <input type="hidden" name="_redirect" value="https://your-site.netlify.app/thanks" />
  <button type="submit">Send</button>
</form>
```

**Next.js**

Sur Netlify, un formulaire Next.js ne fonctionnait avec Netlify Forms que via une copie statique dans `public/`, comme `public/__forms.html`, vers laquelle votre composant envoyait. Supprimez ce fichier, retirez tout paramètre `NETLIFY_NEXT_VERIFY_FORMS`, et envoyez depuis le composant vers Ikiform. Le formulaire envoie aussi sans JavaScript, grâce à son `action`.

`app/contact/contact-form.tsx`:

```tsx
"use client";

import { type FormEvent, useState } from "react";

const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";

export function ContactForm() {
  const [state, setState] = useState<"idle" | "sending" | "sent">("idle");
  const [error, setError] = useState("");

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setState("sending");
    setError("");
    try {
      const response = await fetch(ENDPOINT, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(event.currentTarget),
      });
      const result = await response.json();
      if (result.ok) return setState("sent");
      setError(result.error.fields?.message?.[0] ?? result.error.fields?.email?.[0] ?? result.error.message);
    } catch {
      setError("Couldn't send. Check your connection and try again.");
    }
    setState("idle");
  }

  if (state === "sent") return <p role="status">Thanks. We read every message and reply within a day.</p>;

  return (
    <form action={ENDPOINT} method="post" onSubmit={onSubmit}>
      <input name="bot-field" type="text" tabIndex={-1} autoComplete="off" hidden />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" required />
      <label htmlFor="topic">Topic</label>
      <select id="topic" name="topic" defaultValue="question">
        <option value="question">A question</option>
        <option value="bug">Something is broken</option>
        <option value="work">Working together</option>
      </select>
      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" required />
      {error ? <p role="alert">{error}</p> : null}
      <button disabled={state === "sending"}>{state === "sending" ? "Sending" : "Send"}</button>
    </form>
  );
}
```

**Astro**

Une page Astro statique n'a besoin d'aucun JavaScript. Retirez `data-netlify` du formulaire, définissez l'endpoint comme `action`, et construisez la redirection à partir de `site` dans `astro.config.mjs`. La page peut rester prérendue.

`src/pages/contact.astro`:

```astro
---
const endpoint = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";
const thanksUrl = new URL("/thanks", Astro.site).href;
---

<form method="post" action={endpoint}>
  <input name="bot-field" type="text" tabindex="-1" autocomplete="off" hidden />
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required />
  <label for="topic">Topic</label>
  <select id="topic" name="topic">
    <option value="question">A question</option>
    <option value="bug">Something is broken</option>
    <option value="work">Working together</option>
  </select>
  <label for="message">Message</label>
  <textarea id="message" name="message" required></textarea>
  <input type="hidden" name="_redirect" value={thanksUrl} />
  <button>Send</button>
</form>
```

**TanStack Start**

Une app TanStack Start sur Netlify rend les formulaires en React, ce que la détection au déploiement de Netlify ne pouvait pas voir. Envoyez plutôt via une server function, et supprimez la copie statique masquée. Définissez `IKIFORM_SECRET_KEY` dans les variables d'environnement du site sur Netlify. La fonction transmet l'en-tête `Origin` du navigateur, donc les envois depuis `localhost` comptent comme tests gratuits tant que votre espace de travail n'a pas d'offre.

`src/routes/contact.tsx`:

```tsx
import { createFileRoute } from "@tanstack/react-router";
import { createServerFn, useServerFn } from "@tanstack/react-start";
import { getRequestHeader } from "@tanstack/react-start/server";
import { type FormEvent, useState } from "react";

const sendMessage = createServerFn({ method: "POST" })
  .validator((data: unknown) => {
    if (!(data instanceof FormData)) throw new Error("Expected form data");
    return {
      email: String(data.get("email") ?? "").trim(),
      topic: String(data.get("topic") ?? "question"),
      message: String(data.get("message") ?? "").trim(),
      "bot-field": String(data.get("bot-field") ?? ""),
    };
  })
  .handler(async ({ data }) => {
    const origin = getRequestHeader("origin");
    const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
        ...(origin ? { Origin: origin } : {}),
      },
      body: JSON.stringify(data),
    });
    const result = await response.json();
    return result.ok ? { sent: true, error: "" } : { sent: false, error: String(result.error.message) };
  });

export const Route = createFileRoute("/contact")({ component: Contact });

function Contact() {
  const send = useServerFn(sendMessage);
  const [state, setState] = useState({ sent: false, error: "" });
  const [pending, setPending] = useState(false);

  async function onSubmit(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setPending(true);
    try {
      setState(await send({ data: new FormData(event.currentTarget) }));
    } catch {
      setState({ sent: false, error: "Couldn't send. Try again." });
    } finally {
      setPending(false);
    }
  }

  if (state.sent) return <p role="status">Thanks. We read every message and reply within a day.</p>;

  return (
    <form method="post" onSubmit={onSubmit}>
      <input name="bot-field" type="text" tabIndex={-1} autoComplete="off" hidden />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" required />
      <label htmlFor="topic">Topic</label>
      <select id="topic" name="topic" defaultValue="question">
        <option value="question">A question</option>
        <option value="bug">Something is broken</option>
        <option value="work">Working together</option>
      </select>
      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" required />
      {state.error ? <p role="alert">{state.error}</p> : null}
      <button disabled={pending}>{pending ? "Sending" : "Send"}</button>
    </form>
  );
}
```

**React Router**

Avec React Router en framework mode, l'`action` de la route transmet l'envoi. Le `FormData` passe sans modification, donc `bot-field` atteint la vérification honeypot d'Ikiform, et l'en-tête `Origin` du navigateur suit pour que les envois depuis `localhost` comptent comme tests. Retirez la copie statique que vous gardiez pour Netlify.

`app/routes/contact.tsx`:

```tsx
import { data, Form, useNavigation } from "react-router";
import type { Route } from "./+types/contact";

export async function action({ request }: Route.ActionArgs) {
  const form = await request.formData();
  const origin = request.headers.get("origin");
  const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
    method: "POST",
    headers: {
      Accept: "application/json",
      Authorization: `Bearer ${process.env.IKIFORM_SECRET_KEY}`,
      ...(origin ? { Origin: origin } : {}),
    },
    body: form,
  });
  const result = await response.json();
  if (result.ok) return { sent: true, error: "" };
  return data({ sent: false, error: String(result.error.message) }, { status: response.status });
}

export default function Contact({ actionData }: Route.ComponentProps) {
  const sending = useNavigation().state === "submitting";
  if (actionData?.sent) return <p role="status">Thanks. We read every message and reply within a day.</p>;

  return (
    <Form method="post">
      <input name="bot-field" type="text" tabIndex={-1} autoComplete="off" hidden />
      <label htmlFor="email">Email</label>
      <input id="email" name="email" type="email" required />
      <label htmlFor="topic">Topic</label>
      <select id="topic" name="topic" defaultValue="question">
        <option value="question">A question</option>
        <option value="bug">Something is broken</option>
        <option value="work">Working together</option>
      </select>
      <label htmlFor="message">Message</label>
      <textarea id="message" name="message" required />
      {actionData?.error ? <p role="alert">{actionData.error}</p> : null}
      <button disabled={sending}>{sending ? "Sending" : "Send"}</button>
    </Form>
  );
}
```

**SvelteKit**

Une page SvelteKit sur Netlify peut envoyer directement depuis le navigateur, sans form action de votre côté. L'attribut `action` garde le formulaire fonctionnel avant l'hydratation. Supprimez toute copie prérendue du formulaire ajoutée pour Netlify.

`src/routes/contact/+page.svelte`:

```svelte
<script lang="ts">
  const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";

  let sent = $state(false);
  let sending = $state(false);
  let error = $state("");

  async function send(event: SubmitEvent) {
    event.preventDefault();
    sending = true;
    error = "";
    try {
      const response = await fetch(ENDPOINT, {
        method: "POST",
        headers: { Accept: "application/json" },
        body: new FormData(event.currentTarget as HTMLFormElement),
      });
      const result = await response.json();
      if (result.ok) sent = true;
      else error = result.error.message;
    } catch {
      error = "Couldn't send. Check your connection and try again.";
    }
    sending = false;
  }
</script>

{#if sent}
  <p role="status">Thanks. We read every message and reply within a day.</p>
{:else}
  <form method="post" action={ENDPOINT} onsubmit={send}>
    <input name="bot-field" type="text" tabindex="-1" autocomplete="off" hidden />
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required />
    <label for="topic">Topic</label>
    <select id="topic" name="topic">
      <option value="question">A question</option>
      <option value="bug">Something is broken</option>
      <option value="work">Working together</option>
    </select>
    <label for="message">Message</label>
    <textarea id="message" name="message" required></textarea>
    {#if error}<p role="alert">{error}</p>{/if}
    <button disabled={sending}>{sending ? "Sending" : "Send"}</button>
  </form>
{/if}
```

**Nuxt**

Dans Nuxt, le composant envoie depuis le navigateur avec `$fetch`, donc il n'y a pas de route serveur à déployer. `$fetch` lève une exception sur une réponse autre que `2xx`, et l'enveloppe d'erreur d'Ikiform se trouve dans le `data` de l'erreur. Retirez le formulaire statique masqué de `public/` et le champ `form-name`.

`app/components/ContactForm.vue`:

```vue
<script setup lang="ts">
const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";
const sent = ref(false);
const sending = ref(false);
const error = ref("");

async function send(event: Event) {
  sending.value = true;
  error.value = "";
  try {
    await $fetch(ENDPOINT, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(event.target as HTMLFormElement),
    });
    sent.value = true;
  } catch (failure) {
    const data = (failure as { data?: { error?: { message?: string } } }).data;
    error.value = data?.error?.message ?? "Couldn't send. Check your connection and try again.";
  } finally {
    sending.value = false;
  }
}
</script>

<template>
  <p v-if="sent" role="status">Thanks. We read every message and reply within a day.</p>
  <form v-else :action="ENDPOINT" method="post" @submit.prevent="send">
    <input name="bot-field" type="text" tabindex="-1" autocomplete="off" hidden />
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required />
    <label for="topic">Topic</label>
    <select id="topic" name="topic">
      <option value="question">A question</option>
      <option value="bug">Something is broken</option>
      <option value="work">Working together</option>
    </select>
    <label for="message">Message</label>
    <textarea id="message" name="message" required></textarea>
    <p v-if="error" role="alert">{{ error }}</p>
    <button :disabled="sending">{{ sending ? "Sending" : "Send" }}</button>
  </form>
</template>
```

**React**

Une application React monopage sur Netlify envoyait des données urlencoded vers `/` avec un champ `form-name`, et avait besoin d'une copie statique dans `index.html` pour la détection. Elle envoie maintenant le `FormData` vers l'endpoint. Seule la requête change :

**Avant** (`ContactForm.tsx`)

```tsx
const body = new URLSearchParams(new FormData(event.currentTarget) as unknown as Record<string, string>);
body.set("form-name", "contact");
await fetch("/", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: body.toString(),
});
```

**Après** (`ContactForm.tsx`)

```tsx
const response = await fetch("https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx", {
  method: "POST",
  headers: { Accept: "application/json" },
  body: new FormData(event.currentTarget),
});
const result = await response.json();
if (!result.ok) setError(result.error.message);
```

Supprimez le `<form netlify>` masqué de `index.html` une fois que plus rien n'envoie vers Netlify.

**Vue**

Le même envoi côté navigateur dans un composant Vue monofichier. Retirez de `index.html` le formulaire masqué qui permettait à Netlify de le détecter.

`src/components/ContactForm.vue`:

```vue
<script setup lang="ts">
import { ref } from "vue";

const ENDPOINT = "https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx";
const state = ref<"idle" | "sending" | "sent">("idle");
const error = ref("");

async function send(event: Event) {
  state.value = "sending";
  error.value = "";
  try {
    const response = await fetch(ENDPOINT, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(event.target as HTMLFormElement),
    });
    const result = await response.json();
    if (result.ok) {
      state.value = "sent";
      return;
    }
    error.value = result.error.message;
  } catch {
    error.value = "Couldn't send. Check your connection and try again.";
  }
  state.value = "idle";
}
</script>

<template>
  <p v-if="state === 'sent'" role="status">Thanks. We read every message and reply within a day.</p>
  <form v-else :action="ENDPOINT" method="post" @submit.prevent="send">
    <input name="bot-field" type="text" tabindex="-1" autocomplete="off" hidden />
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required />
    <label for="topic">Topic</label>
    <select id="topic" name="topic">
      <option value="question">A question</option>
      <option value="bug">Something is broken</option>
      <option value="work">Working together</option>
    </select>
    <label for="message">Message</label>
    <textarea id="message" name="message" required></textarea>
    <p v-if="error" role="alert">{{ error }}</p>
    <button :disabled="state === 'sending'">{{ state === "sending" ? "Sending" : "Send" }}</button>
  </form>
</template>
```

> Les versions TanStack Start et React Router envoient depuis votre serveur. Les versions côté serveur envoient avec une clé secrète, donc Ikiform ignore **Allowed domains** et sa vérification humaine. Chaque envoi vient alors de l'IP de votre serveur, et la limite Standard de 5 par minute et par visiteur compte tous vos visiteurs ensemble. Choisissez la [limite de débit](https://ikiform.com/fr/docs/rate-limits.md) Relaxed ou Custom pour un formulaire que vous envoyez via un serveur, et gardez `IKIFORM_SECRET_KEY` dans des variables d'environnement réservées au serveur.

Chaque version garde les mêmes noms de champs que sous Netlify, donc les e-mails de notification et les colonnes CSV restent familiers. La [comparaison avec Netlify Forms](https://ikiform.com/alternatives/netlify-forms) contient la correspondance complète des attributs, y compris `data-netlify-recaptcha` et les inputs de fichier.

## Deploy previews et domaines autorisés

Netlify donne à chaque pull request sa propre adresse, comme `deploy-preview-42--your-site.netlify.app`. Ce n'est pas un sous-domaine de `your-site.netlify.app`, donc lister l'adresse de votre site sous **Allowed domains** ne couvre pas les previews, et les envois depuis une preview finissent en spam avec `origin_mismatch`.

- Ajoutez `your-site.netlify.app` et votre domaine personnalisé pour la production.
- Ajoutez un hôte de preview précis pendant que vous le testez, puis retirez-le.
- N'ajoutez pas `netlify.app` seul. Tous les sites sur Netlify seraient autorisés à envoyer vers votre formulaire.
- Ou faites pointer les previews vers un second formulaire Ikiform sans domaines autorisés, via une variable d'environnement, et gardez la production stricte.

## Basculer sans perdre de soumissions

1. Téléchargez les soumissions passées de chaque formulaire en CSV depuis la section **Forms** du site. Ikiform n'a pas d'import.
2. Déployez le nouveau formulaire sur une preview et envoyez un test. Vérifiez les noms de champs dans le tableau de bord Ikiform.
3. Fusionnez en production et envoyez un autre test depuis le domaine de production.
4. Remplacez tout webhook sortant de Netlify par un [webhook](https://ikiform.com/fr/docs/webhooks.md) Ikiform. Netlify signe avec un jeton JWS ; Ikiform utilise les en-têtes Standard Webhooks, donc votre vérificateur change aussi.
5. Quand aucun envoi n'a atteint Netlify depuis quelques jours, désactivez la détection de formulaires dans les paramètres Forms du site.

> Netlify accepte l'envoi de fichiers et passe chaque soumission dans Akismet. L'envoi de fichiers n'est pas encore pris en charge. Un envoi avec un fichier reçoit `422 files_not_supported`. Si un formulaire a besoin de fichiers, gardez ce formulaire-là sur Netlify Forms et déplacez les autres.

## Vérifier que tout fonctionne sur Netlify

1. Dans **Allowed domains** du formulaire, ajoutez le domaine de votre site, plus `localhost` pendant le développement. Laissez vide pour accepter les envois de partout.
2. Déployez une preview, ajoutez son hôte et envoyez le formulaire depuis cette preview.
3. Ouvrez **Submissions** dans le tableau de bord. La nouvelle soumission y est, avec tous les champs envoyés.
4. Vérifiez que les champs sont `email`, `topic` et `message`, sans `form-name` ni `bot-field`.
5. Ouvrez l'onglet **Forms** du site dans Netlify et vérifiez que le test n'y figure pas.
6. Envoyez une fois avec `bot-field` rempli. L'envoi est stocké comme spam et ne déclenche rien.
7. Vérifiez la boîte de réception de chaque destinataire des notifications. Chacun reçoit un e-mail avec les champs, et **Reply** répond à l'expéditeur quand le formulaire a un champ `email`.

## Pièges

| Problème | Que faire |
| --- | --- |
| Un champ `form-name` apparaît dans Ikiform | L'input masqué `form-name` est toujours dans le formulaire, ou votre code le définit encore. Retirez-le ; Ikiform identifie le formulaire par l'URL. |
| Le build Next.js échoue en mentionnant les formulaires | Un attribut `netlify` ou `data-netlify` est encore dans votre code React. Retirez-le, ainsi que `public/__forms.html`. |
| Les previews envoient en spam | L'hôte de preview ne figure pas dans **Allowed domains**. Ajoutez-le pendant vos tests, ou utilisez un second formulaire pour les previews. |
| Chaque envoi est marqué comme spam, même les vrais | **Honeypot field** est encore `_gotcha` alors que votre input est `bot-field`, ou l'inverse. Faites-les correspondre. |
| `422 files_not_supported` | Le formulaire a un `<input type="file">` avec un fichier choisi. L'envoi de fichiers n'est pas encore pris en charge ; retirez l'input ou demandez plutôt un lien. |
| `429 rate_limited` | Un visiteur a envoyé plus que ce que permet la limite de débit du formulaire. Standard autorise 5 envois par minute et par visiteur. Attendez la durée de `Retry-After`, ou choisissez Relaxed ou Custom pour les formulaires qui envoient depuis une seule IP partagée. |

## Questions

### Que se passe-t-il quand un site Netlify dépasse 100 soumissions de formulaire ?

Sur les anciennes offres, Netlify fait passer le site à Forms Level 1, qui inclut 1 000 soumissions par mois, et le facture en fin de cycle de facturation. Sur l'ancien niveau gratuit, atteindre une limite met en pause tous les sites du compte jusqu'à ce que vous passiez à une offre supérieure.

### Netlify Forms est-il gratuit sur les nouvelles offres à crédits ?

La documentation de Netlify indique que les soumissions de formulaire sont gratuites et illimitées sur les offres à crédits. Le piège, c'est le site lui-même : quand une équipe gratuite épuise ses crédits mensuels, ses projets sont mis en pause et ne reçoivent pas de soumissions de formulaire.

### Puis-je garder l'hébergement sur Netlify et utiliser Ikiform pour les formulaires ?

Oui. Peu importe à Ikiform où la page est hébergée. Retirez les attributs Netlify du formulaire, définissez son action sur votre endpoint Ikiform, et Netlify Forms cesse de le voir.

### Ai-je encore besoin d'un formulaire statique masqué pour React ou Next.js ?

Non. Cette copie n'existe que pour que l'étape de déploiement de Netlify trouve le formulaire. Ikiform reçoit les envois sur une URL, donc supprimez la copie et envoyez depuis votre composant.

### Ikiform est-il gratuit ?

Non, il n'y a pas d'offre gratuite. Les tests sont gratuits : vous pouvez envoyer 50 soumissions de test par mois depuis localhost avant de payer. Pour passer en production, Pro commence à 6 $/mois pour 500 soumissions, ou vous pouvez payer une seule fois 10 000 soumissions pour 49 $ ou 50 000 soumissions pour 149 $, avec des crédits qui n'expirent jamais.

## Autres guides

- [Dépasser les formulaires intégrés](https://ikiform.com/fr/guides/website-builder-forms.md): Quand les formulaires de Webflow, Netlify, Carrd ou Framer atteignent un plafond ou manquent d'une fonctionnalité, gardez le formulaire que vous avez conçu et faites-le pointer vers un backend de formulaires.
- [Limite de soumissions Webflow](https://ikiform.com/fr/guides/website-builder-forms/webflow-submission-limit.md): L'offre gratuite Starter de Webflow cesse de collecter après 50 soumissions de formulaire par site et les sites exportés n'en reçoivent aucune, alors faites plutôt pointer le Form Block vers Ikiform.
- [Formulaires Framer](https://ikiform.com/fr/guides/website-builder-forms/framer-forms.md): Les formulaires Framer envoient déjà vers l'e-mail, Sheets ou un webhook ; ajoutez Ikiform comme webhook pour des soumissions stockées et filtrées, des alertes d'équipe et davantage de destinations.
- [Formulaires Carrd](https://ikiform.com/fr/guides/website-builder-forms/carrd-forms.md): Le formulaire de contact de Carrd ne fait que vous envoyer un e-mail et les formulaires personnalisés nécessitent Pro Plus, alors utilisez Send to URL sur Plus ou une intégration HTML sur Standard pour stocker chaque soumission.
