Liste d'attente pour un nouveau SaaS7 min de lecture
Comment ajouter un formulaire de liste d'attente en HTML simple à n'importe quelle landing page
Une page de liste d'attente complète en HTML simple, sans build, qui fonctionne sans JavaScript, remercie sur place quand il se charge, et se replie si besoin.
Écrivez un formulaire HTML normal qui envoie l'e-mail à votre endpoint Ikiform et redirige vers une page de remerciement : il fonctionne ainsi sur n'importe quel hébergeur sans aucun JavaScript. Ajoutez ensuite un petit script qui envoie le même formulaire avec fetch et affiche le remerciement sur place, et qui rend la main à l'envoi classique chaque fois qu'il ne peut pas aller au bout, par exemple quand la vérification humaine est activée.
Une page de liste d'attente n'a besoin ni de framework, ni d'étape de build, ni de serveur. Quatre fichiers statiques et un backend de formulaires suffisent, et la page se charge plus vite que tout ce qu'exporte un créateur de sites. Cette page construit l'ensemble, couche par couche, pour que chaque couche fonctionne seule.
Ce qui compte sans étape de build
- Le formulaire est l'intégration. Un simple
<form>avec uneactionconstitue toute la connexion à Ikiform. Pas de package, pas de clé d'API, rien à compiler. - JavaScript est une amélioration, pas une obligation. La page doit collecter des inscriptions quand le script est bloqué, lent ou cassé. Chaque couche ci-dessous s'ajoute à la précédente et se replie sur elle.
- Le script ne doit jamais bloquer quelqu'un. Si
fetchéchoue ou si Ikiform demande une vérification humaine quefetchne peut pas exécuter, le script rend le formulaire au navigateur pour un envoi classique. - L'hébergement peut être n'importe où. GitHub Pages, Netlify, Cloudflare Pages, un bucket S3 ou un hébergement mutualisé servent tous ces fichiers tels quels.
| Couche | Ce qu'elle ajoute | Si elle manque |
|---|---|---|
| Formulaire HTML | Envoie l'e-mail, redirige vers thanks.html | Rien ne fonctionne, elle passe donc en premier |
| CSS | Une page lisible en mode clair et sombre | Un formulaire sobre mais fonctionnel |
| Script | Remerciement sur place, erreurs de champ, pas de changement de page | L'envoi classique et la redirection |
- Avec JavaScript désactivé, le navigateur envoie le formulaire, Ikiform redirige en 303 vers votre URL _redirect, et le visiteur voit thanks.html.
- Avec le script chargé, il envoie avec fetch et demande du JSON. Ikiform répond 201 ou une erreur, et le script affiche le résultat sur la même page.
- Si fetch échoue, ou si Ikiform répond challenge_required, le script appelle form.submit().
- Cet envoi classique passe par la page de vérification humaine d'Ikiform si besoin et se termine sur thanks.html.
Les fichiers
La page
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Acme is almost here</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>Acme is almost here</h1>
<p>Invoices that chase themselves. Leave your email and we'll invite you first.</p>
<form id="waitlist" action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="post">
<label for="email">Email</label>
<div class="row">
<input id="email" name="email" type="email" autocomplete="email" required placeholder="you@company.com">
<button>Join the waitlist</button>
</div>
<input type="hidden" name="_redirect" value="https://example.com/thanks.html">
<input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
<p class="message" role="status" aria-live="polite"></p>
</form>
</main>
<script src="waitlist.js" defer></script>
</body>
</html>_redirectenvoie le navigateur versthanks.htmlaprès un envoi classique. Il ne fonctionne que pour une URLhttps:sur l'un des Allowed domains du formulaire : ajoutez-y donc votre domaine. Redirect after submit dans les réglages du formulaire fait la même chose sans l'input masqué.- L'input
_gotchaest le honeypot. Les humains ne le voient jamais ; les bots qui remplissent tous les inputs sont stockés comme spam. aria-live="polite"fait annoncer les messages du script par les lecteurs d'écran sans déplacer le focus.- La balise script utilise
defer: elle s'exécute après la création du formulaire et ne bloque jamais l'affichage de la page.
Le script d'amélioration
const form = document.getElementById("waitlist");
const message = form.querySelector(".message");
const button = form.querySelector("button");
const key = crypto.randomUUID();
form.addEventListener("submit", async (event) => {
event.preventDefault();
button.disabled = true;
message.textContent = "Joining…";
try {
const response = await fetch(form.action, {
method: "POST",
headers: { Accept: "application/json", "Idempotency-Key": key },
body: new FormData(form),
});
const result = await response.json();
if (result.ok) {
form.replaceChildren(Object.assign(document.createElement("p"), {
textContent: "You're on the list. We'll email you on launch day.",
role: "status",
}));
return;
}
if (result.error.code === "challenge_required") {
form.submit();
return;
}
const wait = response.headers.get("Retry-After");
message.textContent = wait
? `Too many tries. Wait ${wait} seconds and try again.`
: result.error.fields?.email?.[0] ?? result.error.message;
} catch {
form.submit();
return;
}
button.disabled = false;
});Accept: application/jsonfait répondre Ikiform en JSON au lieu d'une redirection, pour que le script puisse afficher le résultat sur place.- La clé d'idempotence est créée une fois par chargement de page. Un double clic, ou une nouvelle tentative après une réponse lente, ne stocke qu'une inscription.
challenge_requiredsignifie que la vérification anti-spam du formulaire est réglée sur Ikiform et quefetchn'a envoyé aucun jeton.form.submit()envoie de façon classique, ce qui affiche la page de vérification d'Ikiform puis la page de remerciement. Il ne déclenche pas à nouveau l'événementsubmit, il n'y a donc pas de boucle.- Une erreur réseau prend le même repli. Si Ikiform était injoignable, l'envoi classique affiche l'erreur du navigateur, ce qui reste plus honnête qu'un bouton bloqué.
- Un
429litRetry-Afteret indique combien de temps attendre.
La page de remerciement
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>You're on the list</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>You're on the list</h1>
<p>We'll email you the day Acme opens. Nothing before that.</p>
<p><a href="/">Back to the page</a></p>
</main>
</body>
</html>Les styles
body { margin: 0; font: 16px/1.5 system-ui, sans-serif; color: #111; background: #fff; }
main { max-width: 34rem; margin: 0 auto; padding: 18vh 1rem 4rem; }
h1 { font-size: 2.25rem; line-height: 1.1; margin: 0 0 0.75rem; }
label { display: block; font-weight: 600; margin: 1.5rem 0 0.375rem; }
.row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
input[type="email"] { flex: 1 1 14rem; font: inherit; padding: 0.625rem 0.75rem; border: 1px solid #ccc; border-radius: 0.5rem; }
button { font: inherit; padding: 0.625rem 1rem; border: 0; border-radius: 0.5rem; background: #111; color: #fff; cursor: pointer; }
button:disabled { opacity: 0.6; cursor: progress; }
.message { min-height: 1.5em; margin: 0.5rem 0 0; }
@media (prefers-color-scheme: dark) {
body { color: #eee; background: #111; }
input[type="email"] { background: #1b1b1b; color: inherit; border-color: #444; }
button { background: #eee; color: #111; }
}example.com, mettez à jour _redirect et le lien de retour. Ikiform ignore un _redirect qu'il ne peut pas suivre et affiche sa propre page de remerciement hébergée : une incohérence ne fait donc jamais perdre d'inscription.Déployer et tester
Placez les quatre fichiers dans un dossier et téléversez-le sur n'importe quel hébergeur statique. Ajoutez ensuite le domaine de l'hébergeur dans Allowed domains : par exemple username.github.io, your-site.netlify.app ou votre propre domaine. Pendant le travail en local, ajoutez aussi localhost ; servez le dossier avec n'importe quel serveur statique, car une page ouverte via une URL file:// n'envoie pas d'origine.
Vérifiez que tout fonctionne
- Dans Allowed domains du formulaire, ajoutez le domaine de votre site, plus
localhostpendant le développement. Laissez vide pour accepter les envois de partout. - Désactivez JavaScript dans le navigateur et inscrivez-vous. Vous arrivez sur
thanks.html. - Réactivez-le et inscrivez-vous à nouveau. Le formulaire est remplacé par la phrase de remerciement sans quitter la page.
- Réglez Spam check sur Ikiform et inscrivez-vous une fois de plus. La page passe par la vérification, puis par
thanks.html. - Ouvrez Submissions dans le tableau de bord. La nouvelle soumission y est, avec tous les champs envoyés.
- Envoyez avec le honeypot rempli,
_gotcha=bot. L'envoi reçoit quand même une réponse de succès, mais la soumission est stockée comme spam et n'envoie ni e-mail ni webhook.
Pièges
| Problème | Que faire |
|---|---|
| Le navigateur arrive sur la page de remerciement d'Ikiform au lieu de la vôtre | _redirect est ignoré sauf si son domaine figure dans Allowed domains et qu'il s'agit d'une URL https:. Ajoutez le domaine, ou définissez plutôt Redirect after submit dans les réglages du formulaire. |
403 origin_not_allowed, ou tous les envois finissent en spam | Le domaine de la page n'est pas dans les Allowed domains du formulaire. Ajoutez-le, plus localhost pour les tests en local. Les sous-domaines d'un domaine listé sont autorisés. |
| Les envois depuis une page ouverte comme fichier sont refusés ou marqués comme spam | Une page file:// n'envoie pas d'origine. Servez le dossier avec un serveur statique local et ajoutez localhost aux Allowed domains. |
| La phrase de remerciement ne s'affiche jamais, mais les inscriptions arrivent | Le script ne s'est pas chargé : vérifiez le chemin dans l'attribut src, ou que l'hébergeur sert bien les fichiers .js. L'envoi classique fonctionne toujours, c'est pourquoi les inscriptions arrivent. |
402 test_limit_reached | L'espace de travail n'a pas d'offre et a utilisé ses 50 tests gratuits depuis localhost ce mois-ci. Choisissez une offre, ou utilisez Send test dans le tableau de bord. |
La documentation des formulaires HTML liste tous les champs réservés, et le modèle de liste d'attente génère une version avec nom et rôle. L'export de la liste et l'e-mail de lancement sont dans le guide principal.
Questions
Oui. Un formulaire HTML simple envoie l'e-mail à votre endpoint Ikiform, et Ikiform redirige le navigateur vers votre page de remerciement. JavaScript n'ajoute que le message sur place.
N'importe où on sert des fichiers statiques : GitHub Pages, Netlify, Cloudflare Pages, S3 ou un hébergement mutualisé. Le formulaire envoie à Ikiform, l'hébergeur n'exécute donc jamais de code.
Ikiform répond 403 challenge_required. Le script de ce guide le détecte et envoie le formulaire de façon classique, ce qui affiche la page de vérification puis votre page de remerciement.
Non. Ikiform n'a pas de pages de formulaire hébergées. Vous placez le formulaire sur votre propre site, dans n'importe quel créateur de sites ou framework, et le faites pointer vers votre endpoint Ikiform.
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.
Une étape vous bloque, ou vous voulez un guide pour votre cas ? Écrivez à hello@ikiform.com.