Formulaire de capture de leads

Formulaire de capture de leads6 min de lecture

Créer un formulaire de demande de projet pour une agence ou un freelance

Un formulaire de démarrage de projet pour studios et freelances, qui trie les demandes en chaudes, tièdes et hors cible selon le budget et le calendrier, avant que quiconque ne lise le brief.

Preet SutharFondateur, Ikiform

Demandez les services sous forme de cases à cocher, le budget et la date de début en choix fixes, et une description assez longue pour juger de l'adéquation. Envoyez chaque demande par webhook à un petit relais qui la trie en file chaude, tiède ou hors cible selon le budget et le calendrier. Répondez ensuite à la file chaude le jour même, et déclinez poliment la file hors cible dans la journée, car ces deux réponses construisent votre réputation.

Ce qui change avec une demande de projet

Une demande de devis demande le prix d'un travail connu. Une demande de projet pose une question plus large : sommes-nous faits pour travailler ensemble ? Le visiteur est souvent encore en train de définir le projet, et vous décidez s'il vaut un appel de découverte. Pour un studio ou un freelance, ce qui manque, ce ne sont pas les leads, ce sont les heures d'associés passées à lire des briefs qui n'auraient jamais abouti.

Ce formulaire recueille donc assez de structure pour trier avant de lire. Trois réponses suffisent : ce dont ils ont besoin, à peu près ce qu'ils peuvent dépenser, et quand. Tout ce dont vous voudriez discuter tient dans une longue description, lue en entier seulement quand les réponses structurées disent que ça en vaut la peine.

Comment un relais trie les demandes de projet en filesdemandeservices,budget, débutrelaisvérifie, notebudgetetdébut ?file chaude30 k$ et plus,démarrageprochefile tièderéponse sousdeux joursfile horsciblerefus poliwebhookélevéfaible ou plus tardComment un relais trie les demandes de projet en filesdemandeservices, budget,débutrelaisvérifie, notebudget etdébut ?file chaude30 k$ et plus,démarrage prochefile tièderéponse sousdeux joursfile horsciblerefus poliwebhookélevéfaible ou plus tard
  1. La demande arrive sous forme de webhook signé avec les services, le budget et la date de début.
  2. Le relais vérifie la signature et note le budget et le calendrier.
  3. Il vérifie le score.
  4. Un budget de 30 000 $ ou plus avec un démarrage sous trois mois va dans la file chaude.
  5. Un budget plus faible ou un démarrage plus tardif va dans la file tiède.
  6. Moins de 10 000 $ pour autre chose qu'un site web va dans la file hors cible, pour un refus rapide et aimable.
Les files sont des canaux de chat. Personne n'est rejeté automatiquement : une personne répond toujours à chaque file, dans un ordre différent.

Les champs

Pour un formulaire plus léger avec un seul sujet, partez du modèle de formulaire de contact. Celui-ci ajoute les trois questions de tri. Cochez plusieurs services dans l'aperçu pour les voir stockés sous forme de liste.

Aperçu

Exécute le validateur d'Ikiform dans votre navigateur. Rien n'est envoyé.

De quoi avez-vous besoin ?
Quand doit-il démarrer ?

Objectifs, public, et à quoi ressemble la réussite.

services est un multi_select, stocké sous forme de tableau comme ["brand", "website"]. website est un champ url : example.com est donc stocké sous la forme https://example.com/.
ChampPourquoi cette forme
servicesDes cases à cocher, car les vrais projets combinent plusieurs services. Arrive sous forme de tableau dans le webhook
budgetObligatoire ici, contrairement à un formulaire de devis. Vos tranches doivent commencer là où commence votre engagement minimum
startEn exploration pour l'instant est une réponse honnête, et utile : elle va dans la file tiède
descriptionAu moins 40 caractères, au plus 4 000. Assez long pour juger de l'adéquation, assez court pour que les gens le terminent

Le formulaire

Les cases à cocher partagent un même name. Le navigateur envoie services=brand&services=website, et Ikiform rassemble les répétitions dans une seule liste. Terminer le nom par [] fonctionne aussi, si votre outillage l'attend.

start-a-project.html
<form action="https://ikiform.com/f/frm_xxxxxxxxxxxxxxxx" method="POST">
  <label for="name">Name</label>
  <input id="name" name="name" autocomplete="name" required />
  <label for="email">Email</label>
  <input id="email" name="email" type="email" autocomplete="email" required />
  <label for="website">Your current website</label>
  <input id="website" name="website" inputmode="url" placeholder="example.com" />

  <fieldset>
    <legend>What do you need?</legend>
    <label><input type="checkbox" name="services" value="brand" /> Brand identity</label>
    <label><input type="checkbox" name="services" value="website" /> Website</label>
    <label><input type="checkbox" name="services" value="app" /> Web or mobile app</label>
    <label><input type="checkbox" name="services" value="seo" /> Search and content</label>
  </fieldset>

  <label for="budget">Budget</label>
  <select id="budget" name="budget" required>
    <option value="under_10k">Under $10,000</option>
    <option value="10k_30k">$10,000 to $30,000</option>
    <option value="30k_75k">$30,000 to $75,000</option>
    <option value="over_75k">Over $75,000</option>
  </select>

  <fieldset>
    <legend>When should it start?</legend>
    <label><input type="radio" name="start" value="this_month" required /> This month</label>
    <label><input type="radio" name="start" value="next_quarter" /> In the next three months</label>
    <label><input type="radio" name="start" value="exploring" /> Exploring for now</label>
  </fieldset>

  <label for="description">Tell us about the project</label>
  <textarea id="description" name="description" rows="6" minlength="40" maxlength="4000" required></textarea>

  <input type="hidden" name="_redirect" value="https://studio.example/inquiry/thanks" />
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden />
  <button>Send inquiry</button>
</form>

Trier les demandes par webhook

Ce serveur Express reçoit chaque demande, la vérifie, choisit une file et publie un court résumé dans le canal Slack de cette file. Il lit le corps brut avec express.raw, car la signature couvre les octets exacts envoyés par Ikiform, et passe les req.headers de Node tels quels à verifyWebhook.

server.ts
import express from "express";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

const BUDGET: Record<string, number> = { under_10k: 0, "10k_30k": 1, "30k_75k": 2, over_75k: 3 };
const START: Record<string, number> = { this_month: 2, next_quarter: 1, exploring: 0 };
const CHANNEL = {
  hot: process.env.SLACK_HOT_LEADS!,
  warm: process.env.SLACK_LEADS!,
  "no-fit": process.env.SLACK_NO_FIT!,
};

function lane(fields: Record<string, unknown>): keyof typeof CHANNEL {
  const budget = BUDGET[String(fields.budget)] ?? 0;
  const start = START[String(fields.start)] ?? 0;
  const services = Array.isArray(fields.services) ? fields.services : [];
  if (budget === 0 && !services.includes("website")) return "no-fit";
  if (budget >= 2 && start >= 1) return "hot";
  return "warm";
}

const app = express();

app.post("/webhooks/inquiries", express.raw({ type: "application/json" }), async (req, res) => {
  let event;
  try {
    event = await verifyWebhook({
      payload: req.body.toString("utf8"),
      headers: req.headers,
      secret: process.env.IKIFORM_WEBHOOK_SECRET!,
    });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return res.status(400).send(error.reason);
    throw error;
  }
  if (event.type !== "submission.created") return res.sendStatus(204);

  const fields = event.data.fields;
  const which = lane(fields);
  const summary = String(fields.description ?? "").slice(0, 280);
  const response = await fetch(CHANNEL[which], {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({
      text: `[${which}] ${fields.name}: ${(fields.services as string[]).join(", ")}, ${fields.budget}, ${fields.start}\n> ${summary}\nmailto:${fields.email}`,
    }),
  });
  res.sendStatus(response.ok ? 204 : 502);
});

app.listen(3000);
  • Adaptez lane() à votre façon de vendre. Les seuils ci-dessus sont un exemple, pas un conseil.
  • Le résumé correspond aux 280 premiers caractères de la description. Le texte complet est dans le tableau de bord et dans event.data.fields.
  • Un 502 quand Slack échoue fait réessayer Ikiform pour la même livraison pendant environ 3 jours : une demande n'est donc pas perdue à cause d'une panne du chat.

Ajoutez l'URL https: publique du serveur sous Webhooks. Si vous préférez ne pas faire tourner de serveur, le même aiguillage fonctionne comme une étape de routeur dans Zapier, Make ou n8n.

Quand vos propres services ressemblent à du spam

Le score de spam inclut des phrases de démarchage connues, comme seo services, backlinks et rank your website, qui ajoutent chacune 2. Si vous vendez du référencement, un vrai client peut écrire exactement ça. Les liens s'additionnent aussi : website est stocké comme un lien, et trois liens ou plus ajoutent 2.

Une vraie demande qui contientScoreRésultat
« We need SEO services » et un site web+2Reçue
La même chose, plus deux liens de concurrents dans la description+2 et +2Reçue, à un signal du seuil
Tout ce qui précède, envoyé deux fois en 24 heures+2, +2 et +3Spam, au-delà de 5

Une option référencement et contenu dans services permet aux clients de dire ce dont ils ont besoin sans taper la phrase. Vérifiez quand même le filtre Spam chaque semaine ; une demande de 50 000 $ perdue coûte plus cher que la lecture de dix spams.

Vérifiez que tout fonctionne

  1. Envoyez avec deux services cochés. La soumission stocke services sous forme de liste de deux éléments.
  2. Envoyez avec Plus de 75 000 $ et Ce mois-ci. Le résumé arrive dans le canal chaud.
  3. Envoyez avec Moins de 10 000 $ et seulement Identité de marque. Il arrive dans le canal hors cible.
  4. Collez une description de 3 000 caractères. L'e-mail de notification coupe la valeur à 500 caractères ; le tableau de bord l'affiche en entier.
  5. Arrêtez votre serveur et envoyez. La livraison affiche des tentatives échouées sous Webhooks, puis réussit quand vous le relancez et choisissez Retry.

Pièges

  • Aucune case cochée. Un groupe de cases vide n'envoie rien, donc le required HTML ne peut pas l'imposer. Ikiform refuse l'envoi avec Choose at least one option ; affichez cette erreur sur la page avec la version fetch du guide de capture de leads.
  • Renommer les options. Changez librement les libellés. Ne changez les valeurs qu'en même temps que le relais, sinon les demandes tombent dans la mauvaise file.
  • Les longs briefs dans l'e-mail. Les e-mails de notification affichent jusqu'à 20 champs et 500 caractères par valeur. La description y est coupée. Les membres de l'espace de travail reçoivent dans l'e-mail un lien vers la soumission complète.
  • Le refus. Ikiform n'envoie rien à la personne qui a rempli le formulaire : un lead hors cible n'entend donc rien si personne ne répond. Un refus de deux lignes avec une recommandation garde la porte ouverte.

Questions

Une étape vous bloque, ou vous voulez un guide pour votre cas ? Écrivez à hello@ikiform.com.