Catalogue des nodes
Tous les types de nodes que tu peux drag-and-drop dans le workflow builder. Pour chaque node : ce qu'il fait, ce qu'il config, et un exemple d'usage.
Les nodes sont organisés en 5 catégories, visibles dans la palette gauche du builder (public/cloaking-builder.html:262) :
- Trigger — point d'entrée du workflow (1 seul)
- Detection — évalue une condition, route vers "detected" ou "clean"
- Action — terminal : redirect, 404, allow, block, log
- Routing — splitte le trafic selon un attribut (device, geo, OS…)
- Destinations — termine vers une URL / landing / offer / produit
Le moteur d'évaluation est dans server.js:7540 (le runtime à chaque click) et dans server.js:6479 (le simulateur — même code).
Convention des sorties
- Un node Detection a 2 sorties :
output_1= "Detected" (la condition est vraie),output_2= "Clean" (la condition est fausse). - Un node Routing a N sorties : une par catégorie (mobile, desktop, tablet, smart TV pour
route_device…), + une dernière "Other / Default" pour les valeurs qui ne matchent rien. - Un node Action terminal n'a pas de sortie — il termine l'évaluation.
Les outputs sont nommés output_1, output_2, etc. dans le JSON Drawflow. Le moteur les indexe à partir de 0 en interne.
1. Trigger
trigger_visitor — Visitor Arrives
Le point d'entrée. Il en faut exactement un par workflow, sinon l'évaluation est skip avec No trigger node found in workflow.
| Field | Type | Notes |
|---|---|---|
| (aucune config) | Toujours {} |
Sortie : Next (la 1ère sortie, qui mène au node suivant).
Exemple d'usage : tous les workflows commencent par ce node. Il est seedé automatiquement quand tu cliques "+ New Workflow" dans l'UI.
2. Detection
Toutes les detection nodes suivent la même logique : si la condition est vraie → sortie 1 ("Detected"), sinon → sortie 2 ("Clean").
check_reviewer_ip — Reviewer IP
Détecte les IPs des reviewers Facebook, Google, TikTok, Bing, Snapchat, Pinterest (liste CIDR codée en dur — voir Filters).
| Field | Type | Notes |
|---|---|---|
| (aucune config) | Vérifie contre toutes les plateformes |
Logic : isReviewerIP(ip) (voir server.js:1681). Si l'IP est dans un des CIDR ranges → detected = true.
Exemple : à mettre en TOUT PREMIER après le trigger. C'est gratuit (CIDR match) et bloque les reviewers avant tout le reste.
check_reverse_dns — Reverse DNS
Fait un reverse DNS lookup sur l'IP et vérifie si le hostname termine par un domaine de reviewer connu (*.facebook.com, *.googlebot.com, etc.).
| Field | Type | Notes |
|---|---|---|
patterns |
array of strings | Optionnel. Override la liste par défaut. Format : suffixes de domaine. |
Logic : dns.reverse(ip) puis test hostname.endsWith(pattern). Cache 1h via reverseDNSCache.
Coût : ~10–20ms pour le premier lookup, puis 0ms (cache).
Exemple : à mettre après check_reviewer_ip — capture les reviewers dont l'IP n'est pas dans la liste CIDR mais dont le hostname trahit l'origine.
check_vpn — VPN / Proxy / Tor
Détecte les connexions cachées via 4 mécanismes combinés.
| Field | Type | Défaut | Notes |
|---|---|---|---|
check_vpn |
boolean | true |
Match ISP contre la liste KNOWN_VPN_ASNS (nordvpn, expressvpn, surfshark…) |
check_proxy |
boolean | true |
Détecte headers proxy (X-Forwarded-For chain > 2, Via, etc.) + flag is_hosting de l'API GeoIP |
check_tor |
boolean | true |
Match ISP contient "tor ", "tor exit", "tor relay" |
Logic : voir server.js:7592. detected = true si n'importe lequel des checks activés trigger.
Exemple : node central de la plupart des workflows. Combine avec check_datacenter pour couvrir les VPN qui passent en mode "résidentiel".
check_datacenter — Datacenter IP
Vérifie si l'ISP contient un mot-clé de datacenter connu (AWS, OVH, Hetzner, Linode, DigitalOcean, Vultr, Contabo, etc. — liste complète dans server.js:1760).
| Field | Type | Notes |
|---|---|---|
| (aucune config) | Liste hard-codée |
Logic : DATACENTER_KEYWORDS.some(k => isp.toLowerCase().includes(k)).
Exemple : derrière check_vpn. Un user résidentiel n'arrive jamais depuis "Amazon Web Services" — si l'ISP contient "aws", c'est presque sûr un bot ou un scraper.
check_bot_ua — Bot User-Agent
Détecte les User-Agents de bots connus (Googlebot, bingbot, curl, wget, Selenium, etc.).
| Field | Type | Notes |
|---|---|---|
| (aucune config) | Liste KNOWN_BOTS dans server.js |
Logic : isBot(ua) — voir server.js:1627.
Exemple : à mettre EN PREMIER ou DEUXIÈME. C'est instantané et bloque déjà 30–50% du trafic bot.
check_fraud_score — Fraud Score
Compare le fraud score combiné (server + JS) à un threshold.
| Field | Type | Défaut | Notes |
|---|---|---|---|
threshold |
integer (0-100) | 50 | Si fraudScore >= threshold → detected |
Logic : detected = fraudScore >= config.threshold. Le score est calculé en amont par calculateFraudScore() (combine UA, IP, headers, geo, CF data, IPQS si configuré).
Exemple : node "fourre-tout" en fin de workflow — pour les visiteurs qui ont passé tous les autres checks mais ont accumulé pas mal de flags suspects.
check_js_fingerprint — JS Fingerprint
Détection basée sur des signaux client-side : canvas fingerprint, WebGL, AudioContext, WebDriver.
| Field | Type | Notes |
|---|---|---|
| (config UI) | Le check tourne dans /cloak.js côté navigateur, le résultat arrive via beacon |
Logic server-side : detected = false (le check ne peut pas s'évaluer server-side — voir server.js:7610). Il faut combiner avec un node delay_check ou le résultat arrive via un beacon JS qui re-trigger le workflow.
Exemple : pour les workflows avancés qui veulent attraper des bots Puppeteer/Playwright/Selenium qui passent tous les checks IP/UA. Combine avec delay_check qui wait 500ms le temps que le JS fingerprint remonte.
check_behavior — Behavioral Check
Détecte les patterns inhumains : pas de mouvement souris, pas de scroll, time-on-page < 1s.
| Field | Type | Notes |
|---|---|---|
| (config UI) | Idem check_js_fingerprint — résultat client-side |
Logic server-side : detected = false (s'évalue côté client uniquement).
Exemple : utile pour les bots headless ultra-furtifs. Souvent overkill pour la plupart des cas.
check_country — Country
Compare le pays géolocalisé (GeoIP ou CF country) contre une liste.
| Field | Type | Défaut | Notes |
|---|---|---|---|
countries |
string (CSV) | "" |
Codes ISO-2 séparés par virgule. Ex : US,CA,GB,AU |
mode |
string | "whitelist" |
whitelist = detected si PAS dans la liste. blacklist = detected si dans la liste. |
Logic : voir server.js:7614. Attention au sens — whitelist route les visiteurs hors liste vers la sortie "Detected" (i.e. typiquement vers safe page).
Exemple whitelist : seul le trafic US/CA est autorisé sur ta money page → countries="US,CA", mode="whitelist", sortie "Detected" → safe page, sortie "Clean" → continue.
Exemple blacklist : bloquer le trafic indien et russe → countries="IN,RU", mode="blacklist", sortie "Detected" → safe page.
check_referrer — Referrer
Vérifie si le referrer HTTP contient un des patterns donnés.
| Field | Type | Défaut | Notes |
|---|---|---|---|
patterns |
string (CSV) | "" |
Patterns de domaine, ex : facebook.com,fb.com,m.facebook.com |
Logic : detected = patterns.some(p => referer.toLowerCase().includes(p)). Case-insensitive.
Exemple : valider que le trafic Meta vient bien de Facebook → patterns="facebook.com,fb.com", sortie "Detected" → continue, sortie "Clean" → safe page (visiteur arrivé sans referrer Meta = suspect).
check_time — Time Rules
Vérifie si l'heure UTC actuelle est dans une plage donnée. Utile pour cloak pendant les heures de bureau des reviewers (Mon-Fri 8am-6pm UTC couvre US + EU).
| Field | Type | Défaut | Notes |
|---|---|---|---|
hours_from |
integer (0-23) | 0 | Heure UTC de début |
hours_to |
integer (0-23) | 23 | Heure UTC de fin |
Logic : detected = utcHour >= hours_from && utcHour <= hours_to.
Exemple "agressive black hat" : hours_from=8, hours_to=18 → safe page pendant les heures de boulot des reviewers, money page le reste du temps.
check_device — Device Type
Match le device type du visiteur contre une liste.
| Field | Type | Défaut | Notes |
|---|---|---|---|
devices |
string (CSV) | "Mobile,Desktop" |
Valeurs possibles : Mobile, Desktop, Tablet, Smart TV |
Logic : detected = devices.includes(uaParsed.device_type).
Exemple : ton offer est mobile-only → devices="Mobile", sortie "Detected" → continue, sortie "Clean" → safe page (desktop = pas le bon trafic).
3. Actions terminales
Ces nodes terminent l'évaluation et déclenchent une réponse HTTP. Pas de sortie.
action_safe_page — Show Safe Page
Redirect 302 vers une URL "safe" (typiquement un blog ou un article).
| Field | Type | Notes |
|---|---|---|
url |
string | URL de destination. Si vide → https://google.com par défaut. |
Logic : res.redirect(config.url || 'https://google.com').
Exemple : url = "https://en.wikipedia.org/wiki/Antivirus_software" pour un workflow McAfee.
action_404 — Return 404
Réponse HTTP 404 brute.
| Field | Type | Notes |
|---|---|---|
| (aucune) | Body = "Page Not Found" |
Logic : res.status(404).send('Page Not Found').
Exemple : pour faire croire à un reviewer que la page n'existe pas (plus discret qu'un redirect).
action_redirect — Redirect URL
Comme action_safe_page mais sémantiquement différent : utilisé pour rediriger un visiteur "blanc" vers une page custom (pas forcément une safe page).
| Field | Type | Notes |
|---|---|---|
url |
string | Destination |
Exemple : geo-redirect en sortie d'un route_country → users IN/PK/BD vers ton offer indienne.
action_block — Block & Blacklist
Réponse HTTP 403 + ajoute l'IP à la blacklist permanente.
| Field | Type | Défaut | Notes |
|---|---|---|---|
blacklist |
boolean | false |
Si true, append à ip_blacklist avec reason "Cloaking workflow block" |
Logic : res.status(403).send('Forbidden') + db.addToBlacklist() si blacklist=true.
Exemple : bot ultra-confirmé (fraud_score ≥ 95 + datacenter + headless) → block + blacklist pour ne plus jamais le voir.
action_allow — Allow (Real Page)
Termine le workflow et continue vers le flow normal de la campagne (landing → offer).
| Field | Type | Notes |
|---|---|---|
| (aucune) |
Logic : break de la boucle workflow, le code continue vers le flow engine.
Exemple : node final sur le chemin "le visiteur est OK". Indispensable — sans ça, le workflow tombe dans un cul-de-sac.
action_log — Log Event
Log un event de fraud sans bloquer. Le visiteur continue.
| Field | Type | Défaut | Notes |
|---|---|---|---|
event_name |
string | "cloak_log" |
Nom de l'event dans fraud_events.event_type |
Logic : db.createFraudEvent({ event_type: config.event_name, … }) puis continue vers la sortie 1.
Exemple : "je veux savoir combien d'iPhone iOS 14 arrivent sur ma campagne, sans rien bloquer" → check_device → si match → action_log event="ios14_visitor" → continue.
4. Routing nodes
Routes le visiteur sur une sortie parmi N selon un attribut. Pas une condition binaire.
route_device — Route by Device
| Sorties | Order |
|---|---|
| 1 | Mobile |
| 2 | Desktop |
| 3 | Tablet |
| 4 | Smart TV |
| N | Other (catch-all) |
Logic : voir server.js:7631. Mapping mobile=0, desktop=1, tablet=2, smart tv=3. Si le device ne match rien → dernière sortie.
Exemple : montrer une landing optimisée Mobile vs Desktop.
route_country — Route by Country
| Field | Type | Notes |
|---|---|---|
group_a |
string CSV | Pays du groupe A. Ex : US,CA,AU,GB (Tier 1) |
group_b |
string CSV | Pays du groupe B. Ex : DE,FR,ES,IT,NL (Tier 2) |
group_c |
string CSV | Pays du groupe C. Ex : IN,PK,BD (Tier 3) |
| ... | Tu peux ajouter autant de groupes que tu as de sorties |
Sorties : une par groupe + une "Other" (catch-all en dernière position).
Logic : pour chaque groupe group_a..z dans l'ordre, premier qui contient le pays gagne. Sinon → dernière sortie. Voir server.js:7639.
Exemple : 3 sorties → Tier 1 (offer high payout) | Tier 2 (offer medium) | Other (safe page).
route_os — Route by OS
| Sorties | Order |
|---|---|
| 1 | Windows |
| 2 | Mac |
| 3 | Android |
| 4 | iOS |
| N | Other |
Mapping fixe (voir server.js:7654) : windows=0, mac/macos=1, android=2, ios/iphone/ipad=3.
route_browser — Route by Browser
| Sorties | Order |
|---|---|
| 1 | Chrome |
| 2 | Safari |
| 3 | Firefox |
| 4 | Edge |
| 5 | Opera |
| 6 | IE |
| N | Other |
route_language — Route by Language
| Field | Type | Notes |
|---|---|---|
languages |
string CSV | Ex : en,fr,de — codes ISO-2 |
Sorties : 1 par langue dans l'ordre du CSV + "Other".
Logic : lang = navigator language[0] → premier match dans languages[] gagne. Voir server.js:7669.
route_ab_split — A/B/C Split
Random weighted split.
| Field | Type | Notes |
|---|---|---|
weight_a |
integer | Poids relatif sortie 1 |
weight_b |
integer | Poids relatif sortie 2 |
weight_c, weight_d, ... |
integer | Pour 3+ sorties |
Sorties : N sorties (autant que tu connectes), labellisées A / B / C / D…
Logic : rand = Math.random() * total_weight, premier cumulative >= rand gagne. Voir server.js:7677.
Exemple : tester 3 safe pages différentes pour voir laquelle "rassure" le plus → 33/33/34.
route_source — Route by Source
Route selon la valeur de sub2 (typiquement l'ID adset/placement).
Sorties : config-driven, une par valeur de sub2 listée.
Exemple : routing adset par adset pour un test isolé.
5. Destinations
Termine le workflow vers une cible spécifique (override le flow normal de la campagne).
dest_url — Redirect to URL
| Field | Type | Notes |
|---|---|---|
url |
string | URL de destination |
Logic : res.redirect(config.url). Override le flow engine.
dest_landing — Show Landing Page
Termine en laissant le flow normal de la campagne servir la landing. Équivalent à action_allow.
dest_offer — Go to Offer
Termine et laisse le flow normal envoyer vers l'offer.
dest_product — Go to Product
Pour le commerce natif — termine vers une product page.
Combinaisons recommandées
Cloak basique anti-bot (3 nodes)
trigger_visitor → check_bot_ua → [Detected] → action_safe_page
→ [Clean] → action_allow
Cloak Meta compliance (5 nodes)
trigger_visitor
→ check_reviewer_ip → [Detected] → action_safe_page
→ [Clean]
→ check_reverse_dns → [Detected] → action_safe_page
→ [Clean]
→ check_vpn → [Detected] → action_safe_page
→ [Clean] → action_allow
Cloak agressif (9 nodes)
trigger_visitor
→ check_reviewer_ip → safe
→ check_reverse_dns → safe
→ check_bot_ua → safe
→ check_vpn → safe
→ check_datacenter → safe
→ check_country (whitelist US/CA/GB/AU) → safe
→ check_fraud_score (threshold 40) → safe
→ action_allow
Cloak + routing geo (combiné)
trigger_visitor
→ check_vpn → [Detected] → action_safe_page
→ [Clean]
→ route_country
Tier 1 (US,CA,AU) → dest_url=https://my-offer.com/tier1
Tier 2 (EU) → dest_url=https://my-offer.com/tier2
Other → action_safe_page
Erreurs courantes
- Le workflow ne fait rien : il manque le node
trigger_visitorou il y en a plusieurs - Tout le trafic est cloaké : tu as inversé une sortie (sortie 1 = Detected, sortie 2 = Clean — pas l'inverse)
- Le
check_js_fingerprintne détecte rien : c'est normal en server-only, il faut le combiner avec undelay_checkou activer le beacon JS check_countrywhitelist bloque tout :mode="whitelist"+countries=""(vide) → personne ne match → tout le monde est routé vers "Detected" → safe page. Vérifie que ta liste de pays est remplie.- Cul-de-sac : un node de détection a une sortie non connectée → le visiteur tombe dans le vide → le code continue vers le flow normal (équivalent allow silencieux)
Voir aussi
- Workflows — créer / éditer / dupliquer / attacher
- Filters — les listes IP / DNS / ASN consommées par les nodes
- Cloaking — index — vue d'ensemble
- Vue d'ensemble — où le cloaking s'insère