Un flow n8n qui capte les visiteurs de site web identifiés au niveau de la personne depuis Warmly et RB2B via leurs webhooks sortants, note chaque personne identifiée selon un barème ICP configurable, écarte tous ceux qui ne correspondent pas, déduplique sur une fenêtre hebdomadaire, interroge Salesforce pour un contact existant et toute action en cours qu’il vaut mieux ne pas perturber, achemine le survivant vers le propriétaire du compte ou vers un pool de SDR de territoire, demande à Claude de rédiger une première prise de contact chaleureuse ancrée sur la page précise que la personne a consultée, et livre le contexte — brouillon inclus — sous forme de notification Slack accompagnée d’un Lead ou d’une Task Salesforce. Le bundle situé à apps/web/public/artifacts/visitor-deanon-to-outreach-n8n/ fournit l’export n8n complet ainsi qu’un _README.md couvrant l’import, les variables d’environnement, la configuration des identifiants, le barème ICP et la vérification par branche.
When to use this
Utilisez-le lorsqu’un outil de dé-anonymisation résout déjà votre trafic anonyme en personnes nommées, mais que le flux brut est inexploitable. RB2B pousse chaque visiteur américain identifié dans un canal Slack sans aucun filtre ICP ; en une semaine, les représentants cessent de le lire parce que la plupart des identifications sont des chercheurs d’emploi, des étudiants, des concurrents et des personnes situées à trois niveaux de votre acheteur. L’Autopilot de Warmly peut agir sur les visites, mais c’est une boîte noire payante sur le palier à 30 000 $/an et il rédige sans voir les opportunités ouvertes de votre CRM. Le symptôme est le même dans les deux cas : des visiteurs identifiés qui correspondent exactement à votre ICP reçoivent le même traitement que le bruit, si bien que personne n’agit vite sur ceux qui comptent.
Ce flow s’intercale entre l’outil de dé-anon et le représentant. Il applique votre barème ICP — fonction du poste, niveau de séniorité, tranche de taille d’entreprise, liste de pays autorisés et intention de page — dans un seul nœud Code que l’équipe ops peut lire et modifier, de sorte que les seuls visiteurs qui atteignent un représentant sont ceux qui méritent une prise de contact chaleureuse. Parce que la dé-anon vous donne une personne et la page qu’elle a consultée, le brouillon de Claude peut faire référence à « vous consultiez la page tarifs » plutôt qu’à une douleur générique du secteur. Cette précision est tout l’intérêt d’agir sur une visite de site web plutôt que sur une liste froide.
C’est aussi le bon schéma lorsque vous utilisez à la fois Warmly et RB2B, ou que vous prévoyez de remplacer l’un par l’autre. Le nœud Normalize Visitor Payload gère les deux formes de webhook ainsi qu’un repli générique, de sorte que la logique d’acheminement, de filtrage et de rédaction en aval ne se soucie pas du fournisseur qui a déclenché.
When NOT to use this
Passez votre chemin si votre outil de dé-anon n’est pas configuré pour envoyer des webhooks sortants. Warmly (Settings → Webhooks) comme RB2B (Integrations → Webhook / Zapier) prennent en charge les webhooks temps réel au niveau de la personne, mais si vous ne les avez pas activés, il n’y a rien à ingérer, et les replis par polling qui fonctionnent pour les données d’intention au niveau du compte n’existent pas pour les révélations au niveau de la personne.
Passez votre chemin si votre volume d’identification est faible et que votre taux de correspondance ICP est déjà élevé. Le palier Standard de RB2B résout environ 250 visiteurs identifiés par mois ; si la plupart sont déjà dans l’ICP parce que votre trafic est étroitement ciblé, un filtre ICP et une couche de suppression CRM ajoutent une infrastructure dont vous n’avez pas besoin — le push Slack que fournit RB2B suffit.
Ne l’utilisez pas pour inscrire automatiquement les visiteurs identifiés dans une séquence froide. Il serait trivial de câbler le brouillon directement dans Instantly ou Smartlead, et c’est exactement le geste agressif qui fait signaler les domaines d’envoi. Une visite de site web n’est un consentement à rien. La conception rédiger-sans-envoyer maintient un humain entre la révélation et l’envoi, ce qui compte davantage pour la dé-anon au niveau de la personne que pour l’intention au niveau du compte, parce que la correspondance est une identité probabiliste, non un formulaire rempli — la précision de RB2B elle-même tourne autour de 50-70 % sur le trafic ICP américain, et la résolution au niveau du compte de Warmly se situe autour de 15-25 % des visiteurs.
Enfin, ce n’est pas un contrôle de conformité. Il peut restreindre la prise de contact à une liste de pays autorisés dans le gate ICP, mais restreindre le snippet au trafic américain dans Warmly/RB2B, passer les personnes identifiées dans votre liste de suppression et examiner le traitement CA/VA/CO/CT avec un conseil juridique se font tous en dehors de n8n.
Setup
Importez le bundle. Déposez apps/web/public/artifacts/visitor-deanon-to-outreach-n8n/visitor-deanon-to-outreach-n8n.json dans n8n via Workflows → Import from File. Un seul point d’entrée : un webhook à /webhook/visitor-deanon sur lequel Warmly et RB2B publient tous deux.
Définissez les variables d’environnement. Le flow utilise des variables d’environnement pour les seuils ICP (ICP_MIN_EMPLOYEES, ICP_MAX_EMPLOYEES, ICP_COUNTRY_ALLOWLIST, ICP_TITLE_ALLOWLIST, ICP_TITLE_DENYLIST), l’instance et le token Salesforce, ainsi que les trois emails de pool SDR et handles Slack. La liste complète et l’emplacement de chaque valeur figurent dans _README.md. Chaque variable possède un repli intégré au code afin que le flow ne lève jamais d’erreur sur une valeur manquante — mais les valeurs par défaut sont volontairement génériques, définissez-les donc avant la mise en production.
Câblez les identifiants. Trois identifiants sont requis :
PLACEHOLDER_ANTHROPIC_CRED_ID — HTTP Header Auth avec x-api-key réglé sur votre clé Anthropic
PLACEHOLDER_SLACK_CRED_ID — HTTP Header Auth avec Authorization: Bearer xoxb-…
PLACEHOLDER_SALESFORCE_CRED_ID — HTTP Header Auth avec Authorization: Bearer <sfdc_token> (ou un identifiant OAuth Connected App pour la production)
Pointez les webhooks vers n8n. Dans Warmly, ajoutez votre URL https://<your-n8n-host>/webhook/visitor-deanon sous Settings → Webhooks. Dans RB2B, utilisez l’intégration Webhook (ou un « Catch Hook » Zapier redirigeant vers la même URL). Aucun identifiant n’est stocké dans n8n pour l’un ou l’autre fournisseur — ils poussent vers vous.
Ajustez le barème ICP. Ouvrez ICP Fit Gate et lisez le bloc de notation. Il attribue des points pour la fonction du poste, le niveau de séniorité, la tranche de taille d’entreprise, le pays et l’intention de page, et laisse passer toute personne au niveau ou au-dessus de ICP_FIT_THRESHOLD (par défaut 3). Ajustez les pondérations de points et le seuil à votre définition de la correspondance avant l’activation.
Vérifiez chaque chemin. Suivez la vérification dans _README.md : publiez un payload clairement dans l’ICP (doit passer et rédiger), un payload clairement hors ICP (doit être écarté au gate), et le même payload dans l’ICP deux fois (le second doit être écarté à la dédup). Exécutez le test de dédup contre le webhook en direct, non contre le bouton Execute Workflow — les données statiques ne persistent que lors des exécutions en production.
What the flow does
Webhook — Visitor Deanon Ingest accepte les requêtes POST et renvoie immédiatement un 202 via Respond 202 Accepted afin que l’appelant du webhook du fournisseur ne soit pas bloqué sur l’appel au LLM. Normalize Visitor Payload est un nœud Code qui détecte la source par la forme du payload — RB2B (identifié par ses champs Business Email / Captured URL), Warmly (identifié par son imbrication contact-plus-entreprise) et un repli générique — et associe chacun à un enregistrement interne unique avec des champs cohérents : firstName, lastName, title, company, domain, email, linkedinUrl, employeeCount, industry, country, pageViewed et referrer. Le champ pageViewed provient du Captured URL de RB2B et du referrer de signal de Warmly — c’est ce qui rend le brouillon chaleureux plutôt que froid.
ICP Fit Gate est le nœud qui distingue ce flow d’un simple routeur d’intention. Il note la personne selon un barème : la fonction du poste par rapport à une allowlist (revops, sales, marketing, growth, founder, product) et une denylist (student, intern, seeking, agency recruiter) ; la séniorité (C-level, VP, Head, Director marquent plus de points) ; la tranche de taille d’entreprise entre ICP_MIN_EMPLOYEES et ICP_MAX_EMPLOYEES ; le pays par rapport à ICP_COUNTRY_ALLOWLIST ; et l’intention de page (une vue de /pricing, /demo ou /product ajoute des points). Si le total est inférieur à ICP_FIT_THRESHOLD, le nœud renvoie un tableau vide et l’exécution s’arrête silencieusement — la personne n’atteint jamais un représentant. Le fitScore et les raisons sont attachés à l’enregistrement afin que la carte Slack d’un visiteur qui passe montre pourquoi il s’est qualifié, et afin qu’un barème mal configuré soit auditable.
Dedup Gate (Static Data) utilise les données statiques de workflow de n8n — $getWorkflowStaticData('global') — pour conserver une clé par personne et par semaine (dedup_<email-or-linkedin>_<ISO-week>). L’échelle hebdomadaire est la bonne fenêtre pour une prise de contact chaleureuse : quelqu’un qui visite votre site trois fois en cinq jours doit générer une seule prise de contact représentant, non trois. Cet objet est la seule façon correcte de persister un état inter-exécutions depuis un nœud Code — l’API REST publique de n8n n’a pas de ressource de données statiques — et le nœud estampille la clé avant tout appel en aval afin que deux révélations concurrentes pour la même personne ne puissent pas passer toutes deux, et élague les clés des semaines antérieures pour que le stockage reste petit.
Salesforce — Contact Lookup interroge un Contact correspondant à l’email de la personne, renvoyant le Contact Id, l’Account Id, le Owner (Id, Name, Email, Slack_Handle__c) et deux signaux de suppression : si le compte a une Opportunity ouverte et si le contact est déjà dans une séquence active (via un champ Current_Sequence__c). Routing & Suppression Logic décide alors. Si le contact existe et qu’un signal de suppression quelconque est positionné — opportunité ouverte, séquence active ou un type de compte client existant — le nœud renvoie un tableau vide : une prise de contact chaleureuse de dé-anon perturberait une action en cours, elle est donc écartée et journalisée. Sinon, si le contact existe, le pic est acheminé vers le propriétaire du compte et le flow créera une Task sur le contact existant. Si aucun contact n’existe — le cas de dé-anon courant, puisque tout l’intérêt est de faire remonter des personnes pas encore dans votre CRM — il est acheminé vers un pool de SDR de territoire (AMER/EMEA/ROW selon le pays) et le flow créera un Lead. Le nœud règle createSObject sur Task ou Lead en conséquence.
Claude — Draft Warm First Touch publie vers l’API Anthropic avec claude-haiku-4-5, un timeout de 8 secondes et neverError: true. Le system prompt bannit le remplissage (« I noticed », « reach out », « touch base », « circle back ») et demande à Claude d’ancrer l’accroche sur la page précise consultée et le rôle de la personne — parce que « saw you were on the pricing page » est actionnable et « I’d love to connect » ne l’est pas. Parse Draft (with fallback) gère un timeout ou un JSON malformé en produisant un brouillon basé sur un modèle marqué draftSource: template-fallback ; les deux chemins produisent draftSubject, draftBody et draftTalkingPoint. Slack — Notify Assignee publie une carte Block Kit dans #visitor-deanon avec le nom de la personne, son titre, son entreprise, son URL LinkedIn, la page qu’elle a consultée, le fitScore et les raisons, ainsi que le brouillon étiqueté « edit before sending ». Salesforce — Create Record POST vers /sobjects/{{ createSObject }} — un Lead pour les personnes inédites, une Task liée au contact existant via WhatId sinon — avec OwnerId réglé uniquement sur un vrai Salesforce User Id (jamais un email, qui renvoie MALFORMED_ID) et omis lors de l’acheminement vers un pool.
Cost reality
Par visiteur identifié qui franchit le gate ICP, claude-haiku-4-5 reçoit environ 500 tokens d’entrée et produit autour de 150 tokens de sortie pour le brouillon à trois champs. Au tarif Haiku 4.5 (~0,80 $/M en entrée, ~4 $/M en sortie), cela représente environ 0,0007 $ par brouillon. Le gate ICP fait le confinement des coûts : si le palier Pro de RB2B fait remonter ~1 000 visiteurs identifiés par mois et que votre barème en laisse passer 30 %, vous rédigez ~300 fois par mois — moins de 0,25 $/mois de dépense Claude. La fenêtre de dédup signifie qu’un visiteur récurrent est facturé une fois par semaine, non par visite.
L’outil de dé-anon est le vrai poste de dépense, non l’automatisation. RB2B va de 159 $/mois (~250 visiteurs identifiés) à 499 $/mois (~1 000) ; les plans payants de Warmly commencent à 15 000 $/an et sa suite Autopilot complète est à 30 000 $/an. n8n auto-hébergé est gratuit ; n8n Cloud Starter à 20 $/mois couvre 5 000 exécutions, gérant confortablement ~300 visiteurs rédigés à ~9 nœuds chacun. L’usage de l’API Salesforce est d’une requête plus une création par visiteur qui passe — quelques centaines d’appels par mois contre une limite Enterprise de 15 000+/jour. Le bot Slack et le point de terminaison webhook n8n sont gratuits.
Failure modes
Le barème ICP écarte silencieusement tout le monde. Un seuil trop strict ou une allowlist de titres qui passe à côté de la façon dont vos acheteurs écrivent réellement leurs titres (p. ex. « RevOps » en sous-chaîne de denylist attrapant accidentellement « Revenue Operations ») signifie que chaque visiteur échoue au gate et que le canal #visitor-deanon reste silencieux — ce qui se lit comme « pas de trafic » alors que c’est en réalité « filtre mal configuré ». Garde-fou : ICP Fit Gate attache le fitScore et les raisons par règle à chaque enregistrement, et la vérification du _README.md inclut la publication d’un payload connu dans l’ICP et la confirmation qu’il passe. Surveillez le taux de passage la première semaine ; s’il est proche de zéro sur du trafic réel, assouplissez le barème.
Les données statiques de dédup ne persistent que lors des exécutions en production.Dedup Gate (Static Data) lit et écrit $getWorkflowStaticData('global'), que n8n ne sauvegarde que lorsque l’exécution est déclenchée en production — jamais lors d’une exécution manuelle Execute Workflow. Tester la dédup en cliquant deux fois sur Execute Workflow fait paraître le gate cassé alors qu’il fonctionne. Garde-fou : activez le workflow et faites un POST vers l’URL du webhook en direct deux fois ; le second POST doit être écarté à la dédup. Le nœud élague les clés de la semaine précédente à chaque exécution, de sorte que le stockage se nettoie de lui-même.
Le brouillon s’adresse à la mauvaise personne. La dé-anon au niveau de la personne est probabiliste — l’identification de RB2B est précise à ~50-70 % sur le trafic ICP américain — de sorte qu’un brouillon peut saluer un nom qui n’est pas réellement celui qui a visité. Garde-fou : le flow n’envoie jamais. La carte Slack commence par l’URL LinkedIn afin que le SDR vérifie l’identité en un clic avant d’éditer et d’envoyer, et le brouillon est étiqueté comme un point de départ dans le system prompt comme dans le message Slack.
La rotation du token Bearer Salesforce bloque les lookups. Un token Bearer brut dans SFDC_ACCESS_TOKEN tourne (toutes les ~2 heures sur les orgs sans politique de session persistante). À son expiration, Salesforce — Contact Lookup renvoie 401 silencieusement (à cause de neverError: true), si bien que chaque visiteur paraît inédit et est acheminé vers un pool en tant que Lead — contournant discrètement la suppression. Garde-fou : surveillez une série de créations de Lead sans aucune création de Task alors même que vous savez que des contacts existants visitent ; pour la production, remplacez le token brut par une Connected App utilisant le flux OAuth 2.0 client-credentials. Le _README.md couvre cela.
vs alternatives
vs Warmly Autopilot. L’agent propre de Warmly peut qualifier et prendre rendez-vous à partir d’une visite, et si vous payez déjà le palier à 30 000 $/an et que vous n’utilisez pas Salesforce comme source de vérité pour la suppression, cela peut suffire. Ce n’est pas le bon outil si vous voulez que la logique ICP et les règles de suppression soient lisibles et auditables par votre équipe ops, si vous utilisez RB2B en parallèle ou à la place de Warmly, ou si vous voulez que la prise de contact soit un brouillon édité par un représentant plutôt qu’un envoi autonome. Ce flow vous donne les trois au coût de n8n et fonctionne pour les deux fournisseurs.
vs RB2B → Slack → triage manuel. Le push Slack natif de RB2B est le statu quo : chaque personne identifiée, aucun filtre ICP, aucune conscience du CRM. Il convient au palier gratuit et fonctionne à faible volume, mais à 1 000 identifications par mois le canal devient un bruit que les représentants ignorent, et il n’y a aucun garde-fou contre le fait de solliciter un contact en plein deal. Ce flow filtre d’abord vers l’ICP et supprime les actions en cours, de sorte que ce qui arrive dans Slack vaut la peine d’être lu.
vs un auto-enroll Zapier dans Instantly/Smartlead. Le geste en un clic est RB2B/Warmly → Zapier → séquenceur froid. Il envoie le plus vite et c’est le plus risqué : aucun contrôle humain sur une identité probabiliste, aucune suppression contre les opportunités ouvertes, et les envois froids vers des personnes fraîchement dé-anonymisées sont le moyen le plus rapide de cramer un domaine d’envoi. Ce flow échange cette vitesse contre un brouillon avec un représentant dans la boucle et une suppression consciente du CRM.
vs une table Clay sur un flux de dé-anon.Clay peut tirer un flux de dé-anon, l’enrichir, appliquer un barème ICP avec des colonnes de formule et pousser vers un séquenceur — et c’est un très bon choix pour les campagnes de prospection par lot. Ce n’est pas piloté par les événements, il y a donc toujours un délai de lot entre la visite et la prise de contact. Utilisez Clay pour la couche hebdomadaire d’enrichissement et de prospection ; utilisez ce flow pour la réponse temps réel, tant que la visite est encore chaude.
# Visitor de-anon to outreach — n8n flow
This bundle contains a complete n8n workflow that turns person-level website de-anonymization signals from **Warmly** and **RB2B** into ICP-filtered, CRM-aware warm outreach. It catches each identified visitor from the vendor's outgoing webhook, scores the person against a configurable ICP rubric (dropping everyone who doesn't fit), deduplicates within a week-level window, checks Salesforce for an existing contact and any active motion, routes the survivor to the account owner or a territory SDR pool, drafts a warm first-touch with Claude anchored to the exact page the person viewed, posts a Slack card to the assignee, and creates a Salesforce Lead (net-new person) or Task (existing contact).
One entry point:
- **Webhook** — `Webhook — Visitor Deanon Ingest` accepts `POST /webhook/visitor-deanon` from Warmly (Settings → Webhooks) and RB2B (Integrations → Webhook / Zapier), or any system that can POST a person-level payload.
## What this flow does
`Normalize Visitor Payload` maps three payload shapes — RB2B (space-cased field names, `Captured URL`), Warmly (nested `contact` / `company` / `signal`), and a generic fallback — into one internal person record. The `pageViewed` field (RB2B `Captured URL` / Warmly signal referrer) is the load-bearing input for the warm draft.
`ICP Fit Gate` is what separates this flow from a plain intent router. It scores each person against a readable rubric — title function (+2), seniority (+1), company-size band (+1), country (+1), high-intent page like `/pricing` or `/demo` (+2) — and hard-drops title-denylist matches (student, intern, agency recruiter, job-seeker) and off-allowlist countries. Anyone below `ICP_FIT_THRESHOLD` (default 3) is dropped and never reaches a rep. The `fitScore` and reasons are attached so a passing visitor's Slack card shows why they qualified, and a misconfigured rubric is auditable from execution history.
`Dedup Gate (Static Data)` uses n8n workflow static data — `$getWorkflowStaticData('global')` — to hold a per-person-per-ISO-week key. Week-level (not day-level) is the right window for warm outreach: someone who visits three times in five days should generate one rep touch. Static data is the only correct way to persist cross-execution state from a Code node — n8n's public REST API has **no** static-data resource — and it only persists for **production** executions (webhook / schedule trigger), not manual runs. The node stamps the key before any external call (race-safe) and prunes prior weeks.
`Salesforce — Contact Lookup` finds an existing contact by exact email and returns the owner plus three suppression signals: open opportunity, active sequence (`Current_Sequence__c`), and customer account type. `Routing & Suppression Logic` suppresses the touch (drops silently) when an existing contact is mid-motion; otherwise it routes an existing clean contact to the account owner (→ Task) or a net-new person to a territory SDR pool (→ Lead).
`Claude — Draft Warm First Touch` generates a three-part draft (subject, body, talking point) anchored to the page viewed. The draft is explicitly a starting point — identity is probabilistic — and the flow never sends. `Slack — Notify Assignee` posts the context and draft to `#visitor-deanon`, leading with the LinkedIn URL for one-click identity verification. `Salesforce — Create Record` writes a Lead or Task.
## Import
1. In n8n, open **Workflows → Import from File** and select `visitor-deanon-to-outreach-n8n.json`.
2. Open the workflow's **Settings** and confirm `Execution Order` is `v1` and `Timezone` matches your business hours (defaults to `America/New_York`). The dedup window rolls over on the ISO-week boundary in UTC; if you need it aligned to a local week, adjust the week derivation in `Dedup Gate (Static Data)`.
3. Set the environment variables in the **Environment variables** section below.
4. Wire the three credentials in the **Credentials** section.
5. Read and tune the **ICP rubric** in `ICP Fit Gate` to your definition of fit.
6. Point the Warmly and RB2B webhooks at your n8n URL (**Webhook setup** below).
7. Activate the workflow only after the **First-run verification** below passes.
## Environment variables
Set these in your n8n instance's environment (n8n Cloud: **Settings → Environment Variables**; self-hosted: your `.env` file or container environment). Every variable has an in-code fallback, so a missing one won't throw — but the ICP defaults are generic, so set them before going live.
| Variable | What it does | Example |
|---|---|---|
| `SFDC_INSTANCE_URL` | Salesforce Setup → Company Information → Salesforce.com Base URL | `https://yourorg.my.salesforce.com` |
| `SFDC_ACCESS_TOKEN` | Salesforce OAuth access token (see note below) | `00D…` |
| `ICP_MIN_EMPLOYEES` | Lower bound of the in-ICP company-size band | `25` |
| `ICP_MAX_EMPLOYEES` | Upper bound of the in-ICP company-size band | `5000` |
| `ICP_FIT_THRESHOLD` | Minimum fit score to pass the gate | `3` |
| `ICP_COUNTRY_ALLOWLIST` | Comma-separated ISO country codes; empty = allow all | `US,CA,GB` |
| `ICP_TITLE_ALLOWLIST` | Comma-separated lowercase title substrings that score +2 | `revops,sales,marketing,growth,founder` |
| `ICP_TITLE_DENYLIST` | Comma-separated lowercase substrings that hard-drop | `student,intern,seeking,recruiter,job` |
| `SDR_POOL_AMER_EMAIL` | SDR pool lead email for AMER territory | `sdr-amer@yourcompany.com` |
| `SDR_POOL_AMER_SLACK` | Slack handle (no @) for AMER SDR pool | `sdr-amer` |
| `SDR_POOL_EMEA_EMAIL` | SDR pool lead email for EMEA territory | `sdr-emea@yourcompany.com` |
| `SDR_POOL_EMEA_SLACK` | Slack handle (no @) for EMEA SDR pool | `sdr-emea` |
| `SDR_POOL_ROW_EMAIL` | SDR pool lead email for ROW territory | `sdr-row@yourcompany.com` |
| `SDR_POOL_ROW_SLACK` | Slack handle (no @) for ROW SDR pool | `sdr-row` |
The `SFDC_ACCESS_TOKEN` rotates. For production, use a Connected App with OAuth 2.0 client-credentials flow and a short-lived token refresh, or the Salesforce OAuth2 credential in n8n instead of the raw Bearer token.
## Credentials
### `PLACEHOLDER_ANTHROPIC_CRED_ID` — Anthropic
Used by `Claude — Draft Warm First Touch`. Generate an API key at `https://console.anthropic.com`. In n8n, add an **HTTP Header Auth** credential with header name `x-api-key` and value set to the key. The node uses `claude-haiku-4-5` to keep latency under ~2 seconds on a typical person payload. Swap to `claude-sonnet-4-6` only if draft quality is consistently off for a segment — roughly 10× the cost.
### `PLACEHOLDER_SLACK_CRED_ID` — Slack
Used by `Slack — Notify Assignee`. Create a Slack app with a bot token (`xoxb-…`) that has `chat:write` scope, and invite the bot to `#visitor-deanon`. In n8n, add an **HTTP Header Auth** credential with header name `Authorization` and value `Bearer xoxb-…`.
### `PLACEHOLDER_SALESFORCE_CRED_ID` — Salesforce
Used by `Salesforce — Contact Lookup` and `Salesforce — Create Record`. For a quick pilot, add an **HTTP Header Auth** credential with header name `Authorization` and value `Bearer <sfdc_token>`. For production, use a Connected App (OAuth 2.0 client credentials) so the token refreshes automatically.
## Salesforce fields used
The flow reads `Current_Sequence__c` on the Contact object as an active-sequence suppression signal, and the standard `Owner.Slack_Handle__c` custom field on User for Slack @-mentions. If your org doesn't have these:
- **`Current_Sequence__c` (Contact, Text)** — set by your sequencer's integration when a contact is enrolled; if you don't populate it, the suppression check simply never fires on that signal (open opportunity and customer type still work). Remove the field from the SOQL in `Salesforce — Contact Lookup` if it doesn't exist, or the query errors.
- **`Slack_Handle__c` (User, Text)** — the owner's Slack handle for @-mentions. If absent, remove it from the SOQL; the flow falls back to no @-mention.
No custom fields are required on Lead or Task — the flow uses only standard fields (`LeadSource`, `Description`, `WhoId`, `WhatId`, etc.).
## Webhook setup
- **Warmly** — **Settings → Webhooks**, add `https://<your-n8n-host>/webhook/visitor-deanon`, save. Configure the orchestrator to fire the webhook on an identified-visitor event.
- **RB2B** — **Integrations → Webhook** (or the **Zapier** integration with a "Catch Hook" → POST to the same URL). RB2B sends person-level fields (LinkedIn URL, First/Last Name, Title, Company Name, Business Email, Website, Industry, Employee Count, Captured URL, Referrer, etc.).
## First-run verification
Run these against the **live** webhook URL (not the Execute Workflow button — static data and production behavior only apply to real webhook executions). Sample payloads are minimal; add fields as needed.
1. **In-ICP passes and drafts.** POST an RB2B-shaped payload for a clearly in-ICP person on a high-intent page:
```bash
curl -X POST https://<your-n8n-host>/webhook/visitor-deanon \
-H 'Content-Type: application/json' \
-d '{"First Name":"Jordan","Last Name":"Lee","Title":"VP Sales","Company Name":"Acme","Website":"acme.com","Business Email":"jordan@acme.com","Employee Count":"400","Industry":"Software","State":"CA","Captured URL":"https://yoursite.com/pricing","LinkedIn URL":"https://linkedin.com/in/jordanlee"}'
```
Expect: a Slack card in `#visitor-deanon` with a fit score ≥ 3 and a draft, and a new Salesforce Lead (no matching contact).
2. **Out-of-ICP drops at the gate.** POST a payload that should fail — a student, or a sub-`ICP_MIN_EMPLOYEES` company:
```bash
curl -X POST https://<your-n8n-host>/webhook/visitor-deanon \
-H 'Content-Type: application/json' \
-d '{"First Name":"Sam","Last Name":"Kim","Title":"Student","Company Name":"University","Website":"uni.edu","Business Email":"sam@uni.edu","Employee Count":"3","State":"NY","Captured URL":"https://yoursite.com/blog/post"}'
```
Expect: no Slack card, no Salesforce record. Check the execution — it should stop at `ICP Fit Gate`.
3. **Dedup drops the repeat.** Re-run the payload from step 1 within the same week.
Expect: no second Slack card. The execution stops at `Dedup Gate (Static Data)`. (This only works against the live webhook — manual runs don't persist static data.)
4. **Existing contact → Task, not Lead.** POST step 1's payload with an email that already exists as a Salesforce Contact whose account has no open opportunity and no active sequence.
Expect: a Task on the existing contact assigned to the account owner (not a Lead), and a Slack card that reads "existing contact → Task."
5. **Suppression holds.** Repeat step 4 with a contact whose account has an open opportunity (or a customer account type).
Expect: no Slack card, no record — the execution stops at `Routing & Suppression Logic`.
## Notes and limits
- **Identity is probabilistic.** RB2B's person-level identification runs roughly 50-70% accurate on US ICP traffic; Warmly resolves ~15-25% of visitors (largely account-level). The Slack card leads with the LinkedIn URL so the SDR verifies before sending. The flow never auto-sends.
- **Compliance is out of scope for this flow.** Restrict the snippet to US traffic in Warmly/RB2B, run identified people through your suppression list, and review CA/VA/CO/CT handling with counsel. The `ICP_COUNTRY_ALLOWLIST` is a routing convenience, not a legal control.
- **Static data self-cleans.** The dedup node prunes prior-week keys on every run, so the store doesn't grow unbounded; no separate maintenance cron is needed.