Formulaires d'inscription
Un formulaire d'inscription autonome, comme dans Mautic : tu le construis dans l'admin, il vit sur une page hébergée par Trackily (
/form/<slug>) et tu peux le coller sur n'importe quel site (un extrait iframe ou HTML pur). Il inscrit à une liste par le chemin habituel (double opt-in, jetables, MX), pose tes étiquettes et garde la preuve du consentement. Disponible à partir de la migration v152.
Pourquoi
Avant la v152, on ne s'inscrivait à une liste que par une landing Trackily liée à cette liste (/api/lead). Un formulaire autonome est une autre porte d'entrée vers la même liste : pour ton blog, ton site vitrine hébergé ailleurs, une page de lien en bio, ou une simple page Trackily partagée telle quelle.
Créer un formulaire
Email Marketing → Formulaires → Nouveau formulaire. Tu règles :
| Réglage | Ce qu'il fait | Bornes |
|---|---|---|
| Nom | le nom interne, jamais montré au public | 120 caractères |
| Liste | la liste où le formulaire inscrit — elle doit être active | obligatoire |
| Champs | l'e-mail (toujours là, obligatoire, en premier) ; en option prénom, nom, téléphone, pays ; et jusqu'à 10 champs personnalisés : texte, liste de choix, case à cocher | clé a-z 0-9 _, 40 caractères |
| Consentement | le texte de la case d'accord, obligatoire pour s'inscrire | 500 caractères |
| Étiquettes | les étiquettes posées à l'inscription | 10 au plus |
| Après l'envoi | un message (« Merci ! ») ou une redirection vers une page à toi (http ou https) | 500 caractères |
| Langue | la langue de la page : français, anglais ou arabe (de droite à gauche) | fr par défaut |
| Bouton | le libellé du bouton (« S'inscrire » par défaut) | 40 caractères |
| Actif | éteint, la page et l'envoi rendent une erreur 404 | — |
L'adresse publique (slug) est tirée du nom (« Newsletter été » → newsletter-ete, suffixé -2 s'il est pris). Tu peux la changer, mais les extraits déjà collés ailleurs cesseront de marcher. 100 formulaires au plus.
Le prénom et le nom refusent les guillemets, chevrons, virgules, points-virgules et caractères de contrôle (« Zoé », « D’Arc » passent ; « Zo" <x@y> » non) : la page signale le champ. Les champs vont dans la fiche du contact : prénom → {{custom.first_name}} (et {{first_name}}), nom → last_name, téléphone → phone, pays → country (et le code pays du contact s'il est écrit en deux lettres, « MA »), un champ personnalisé sous sa clé ({{custom.taille}}).
Le consentement, versionné et prouvé
- La case d'accord est obligatoire côté serveur : sans elle, l'envoi est refusé et la page dit au visiteur de la cocher. Elle n'est jamais pré-cochée. Seules valent accord la valeur
1ouon(formulaire) ettrue(JSON) — « yes », « oui » ou « true » écrit en texte ne valent rien. - Le texte est versionné : le changer crée la version suivante, les anciennes restent lisibles (le tiroir du formulaire, ou
get_email_form). Un formulaire créé sans texte prend le texte par défaut de sa langue — écrit en base, pour que la preuve cite un texte qui existe. - Chaque inscription garde sa preuve dans les événements du contact :
{ formulaire_id, consentement_version, consentement_texte_hash }(l'empreinte SHA-256 du texte affiché), dans l'événementsubscribedet dans un événementconsentement(avec l'IP et le navigateur de l'envoi). En double opt-in, l'événementconsentementest écrit dès l'envoi (statut: pending_confirm) :subscribedn'arrive qu'à la confirmation. - L'IP de la preuve est gardée : l'événement
consentementgarde l'adresse IP et le navigateur de l'envoi, parce qu'ils SONT la preuve de l'accord (qui a coché, d'où, quand). Ils restent avec les autres événements du contact et partent avec lui quand le contact est supprimé. Ils ne servent à rien d'autre (ni score, ni segment, ni statistique), et les journaux du serveur ne contiennent jamais ni l'adresse e-mail ni l'IP. - Un visiteur qui envoie une page ouverte avant que tu changes le texte voit la page se remontrer avec le texte en vigueur, case à recocher : on ne garde jamais un accord donné à un texte qui n'est plus le tien.
Les étiquettes
Les étiquettes choisies sur le formulaire sont posées avec la source « posée par un formulaire » (détail « formulaire n° X »). Elles n'ont pas besoin d'être marquées « depuis un formulaire » : c'est toi qui les as choisies ici. Mais seulement sur une inscription active : en double opt-in, elles attendent la confirmation et sont posées au clic sur le lien. Une étiquette posée par un formulaire ne peut pas être supprimée tant que le formulaire la pose (« utilisée par formulaire Newsletter »).
Limite assumée, comme pour /api/lead : en simple opt-in, qui connaît une adresse peut l'inscrire et lui faire porter tes étiquettes — choisis des étiquettes sans conséquence sensible, ou passe la liste en double opt-in.
Publier
Le tiroir du formulaire montre un aperçu (la page dans un cadre, l'envoi désactivé, même quand le formulaire est éteint) et, sous « Publier », trois choses à copier :
- Le lien de la page —
https://<ton domaine>/form/<slug>: une page autonome, mobile, accessible, sans script, dans la langue du formulaire. À partager tel quel. - L'extrait iframe (recommandé) — la même page dans un cadre, à coller sur n'importe quel site. Isolée de ton site (ni ses scripts ni ses styles ne la touchent) et protégée contre les robots. Avec une redirection configurée, c'est toute la page qui part vers ta page de remerciement, pas seulement le cadre.
- L'extrait HTML pur — un
<form>sans JavaScript qui poste vers/form/<slug>, pour un site qui refuse les iframes ou que tu veux styler toi-même. Un HTML collé une fois ne peut pas porter de jeton anti-robot : à l'envoi, le visiteur passe par une page de validation hébergée (ses informations remontrées, la case d'accord à cocher sur la page de Trackily, un clic). C'est le prix de la protection. Cette page de validation ne se laisse pas encadrer : un autre site ne peut pas la cacher dans un cadre pour faire cocher la case à ton visiteur.
Par l'API (pour un développeur) : POST /form/<slug> accepte aussi du JSON (Content-Type: application/json, mêmes noms de champs : email, prenom, nom, telephone, pays, champ_<clé>, consentement: true, et le jeton _jeton lu sur la page). Réponse : { ok, message, redirection? }. Sans jeton : 400 jeton_requis. Le jeton ne vaut que dans une requête de même origine (la page hébergée, l'iframe) ou d'un serveur (sans en-tête de navigateur, sous la limite par IP) : un navigateur qui l'envoie depuis un autre site (Sec-Fetch-Site, Origin) est traité comme sans jeton.
Anti-abus, sans CAPTCHA
- un champ piège caché (rempli = robot) ;
- un délai minimal de 2 s entre l'affichage et l'envoi, par un jeton signé servi avec la page (valable 24 h ; au-delà, la page de validation se remontre). Les pages de validation et d'erreur, déjà remplies, servent un jeton à 0,5 s. Un jeton sert 5 fois au plus ;
- des limites de débit : 20 envois par 10 minutes par IP (une IPv6 compte par /64), 1 000 par 10 minutes par formulaire — n'y comptent que les envois acceptés : une seule IP qui martèle, ou un robot repéré, n'éteint pas ton formulaire —, 3 par heure par adresse ;
- une confirmation par adresse et par liste toutes les 24 h (double opt-in, toutes les portes d'entrée) : la même adresse postée en boucle ne fait pas partir une demande de confirmation à chaque fois — le contact garde le lien déjà reçu ;
- un corps de 8 Ko au plus et des valeurs bornées.
Un envoi suspect reçoit la même réponse qu'un envoi réussi : le robot n'apprend rien, mais personne n'est inscrit. Il est compté dans suspects (sur 30 jours, et « suspects_24h » pour le jour en cours et la veille, en UTC). Ni cookie, ni session : un envoi venu d'un autre site ne peut rien faire d'autre qu'inscrire.
Une réponse identique pour tous
Inscription réussie, adresse déjà inscrite, liste en double opt-in, adresse refusée par la liste (jetable, sans MX, en suppression) : la même réponse publique, dans le même temps — elle part après un délai fixe (une demi-seconde) et l'inscription se fait ensuite, en fond : la durée de la réponse ne dit rien de l'adresse non plus. Le contenu : — ton message (ou ta redirection), avec en double opt-in « Vérifiez votre boîte mail pour confirmer votre inscription » (une propriété de la liste, pas de l'adresse). Personne ne peut tester si une adresse est chez toi. Une adresse déjà présente sur la liste (inscrite, en attente ou désinscrite) ne voit rien réécrit par le formulaire — ni nom, ni champs, ni IP, navigateur, pays ou source — et compte « déjà là », pas comme une inscription : le public ne corrige pas la fiche d'un contact. Un contact confirmé ne repasse jamais « en attente de confirmation », quelle que soit la porte d'entrée.
Les seules réponses différentes sont celles qu'un humain peut corriger et qui ne disent rien de l'adresse : champ obligatoire vide, adresse mal tapée, case d'accord non cochée — la page se remontre avec le champ signalé.
Statistiques
Sur 30 jours, par formulaire, calculées par le serveur : vues de la page (un compteur journalier, sans identité), envois, inscriptions (une adresse qui passe inscrite ou en attente de confirmation par cet envoi), confirmations (double opt-in), suspects, et le taux de conversion (inscriptions / vues). Les compteurs arrivent en base par paquets, au plus 10 secondes après.
Formulaire indisponible
La page et l'envoi rendent une 404 neutre — la même que pour une adresse qui n'existe pas — quand le formulaire est éteint ou supprimé, ou quand sa liste est désactivée ou supprimée. Un formulaire ne s'enregistre jamais sur une liste inactive ; une liste désactivée après coup le rend indisponible, et l'écran le dit (« Indisponible : la liste « Clients » est désactivée »).
Par MCP
list_email_forms, get_email_form, create_email_form, update_email_form (tier 1) et delete_email_form (niveau 2 : un aperçu et un jeton, puis la suppression). Mêmes règles et mêmes refus que l'écran : requete_invalide (avec le champ), slug_en_double, liste_inactive, trop_de_formulaires, introuvable.
Voir aussi
- Lists — double opt-in, jetables, MX
- Étiquettes des contacts — le catalogue, les règles, le champ
tagsdes landings - Automations — la porte historique : landing liée à une liste (
/api/lead)