Un flujo de n8n que captura visitantes de tu sitio identificados a nivel de persona desde Warmly y RB2B a través de sus webhooks salientes, puntúa a cada persona identificada contra una rúbrica de ICP configurable, descarta a todos los que no encajan, deduplica dentro de una ventana de nivel semanal, consulta Salesforce para ver si existe un contacto y cualquier movimiento activo que convenga no pisar, enruta al sobreviviente hacia el dueño de la cuenta o un pool de SDR por territorio, le pide a Claude que redacte un primer contacto cálido anclado a la página específica que la persona vio, y entrega el contexto —borrador incluido— como una notificación de Slack más un Lead o Task de Salesforce. El paquete en apps/web/public/artifacts/visitor-deanon-to-outreach-n8n/ incluye el export completo de n8n más un _README.md que cubre la importación, las variables de entorno, la configuración de credenciales, la rúbrica de ICP y la verificación por rama.
Cuándo usar esto
Úsalo cuando una herramienta de desanonimización ya está resolviendo tu tráfico anónimo hacia personas con nombre, pero el feed en crudo es inutilizable. RB2B empuja cada visitante identificado de EE. UU. a un canal de Slack sin filtro de ICP; en una semana los reps dejan de leerlo porque la mayoría de las identificaciones son buscadores de empleo, estudiantes, competidores y gente a tres niveles de distancia de tu comprador. El propio Autopilot de Warmly puede actuar sobre las visitas, pero es una caja negra de pago en el tier de $30,000/año y redacta sin ver las oportunidades abiertas de tu CRM. El síntoma en ambos casos es el mismo: los visitantes identificados que encajan exactamente con tu ICP reciben el mismo trato que el ruido, así que nadie actúa rápido sobre los que importan.
Este flujo se ubica entre la herramienta de desanonimización y el rep. Aplica tu rúbrica de ICP —función del puesto, seniority, banda de tamaño de empresa, allowlist de países e intención de página— en un único nodo Code que el equipo de ops puede leer y cambiar, de modo que los únicos visitantes que llegan a un rep son los que valen un contacto cálido. Como la desanonimización te da una persona y la página que vio, el borrador de Claude puede referenciar “estabas viendo la página de precios” en lugar de un dolor genérico de la industria. Esa especificidad es todo el sentido de actuar sobre una visita al sitio en lugar de una lista fría.
También es el patrón correcto cuando corres ambos Warmly y RB2B, o planeas cambiar uno por el otro. El nodo Normalize Visitor Payload maneja ambas formas de webhook y un fallback genérico, así que la lógica de enrutamiento, filtrado y redacción río abajo no le importa cuál proveedor disparó.
Cuándo NO usar esto
Sáltatelo si tu herramienta de desanonimización no está configurada para enviar webhooks salientes. Tanto Warmly (Settings → Webhooks) como RB2B (Integrations → Webhook / Zapier) admiten webhooks a nivel de persona en tiempo real, pero si no los has activado no hay nada que ingerir, y los fallbacks de polling que funcionan para datos de intención a nivel de cuenta no existen para las revelaciones a nivel de persona.
Sáltatelo si tu volumen de identificación es bajo y tu tasa de acierto de ICP ya es alta. El tier Standard de RB2B resuelve aproximadamente 250 visitantes identificados al mes; si la mayoría de esos ya están dentro del ICP porque tu tráfico está muy segmentado, un filtro de ICP y una capa de supresión de CRM agregan infraestructura que no necesitas —el push de Slack que RB2B trae de fábrica es suficiente.
No lo uses para auto-inscribir visitantes identificados en una secuencia fría. Sería trivial cablear el borrador directo a Instantly o Smartlead, y ese es exactamente el movimiento agresivo que hace que marquen tus dominios de envío. Una visita al sitio no es consentimiento para nada. El diseño de borrador-sin-envío mantiene a un humano entre la revelación y el envío, lo cual importa más para la desanonimización a nivel de persona que para la intención a nivel de cuenta, porque el match es una identidad probabilística, no el envío de un formulario —la precisión propia de RB2B ronda el 50-70% en tráfico de ICP de EE. UU., y la resolución a nivel de cuenta de Warmly aterriza en torno al 15-25% de los visitantes.
Por último, esto no es un control de cumplimiento. Puede restringir el outreach a una allowlist de países en el gate de ICP, pero restringir el snippet al tráfico de EE. UU. en Warmly/RB2B, pasar a las personas identificadas por tu lista de supresión, y revisar el manejo de CA/VA/CO/CT con asesoría legal ocurren todos fuera de n8n.
Configuración
Importa el paquete. Suelta apps/web/public/artifacts/visitor-deanon-to-outreach-n8n/visitor-deanon-to-outreach-n8n.json en n8n vía Workflows → Import from File. Un único punto de entrada: un webhook en /webhook/visitor-deanon al que tanto Warmly como RB2B publican.
Configura las variables de entorno. El flujo usa variables de entorno para los umbrales de ICP (ICP_MIN_EMPLOYEES, ICP_MAX_EMPLOYEES, ICP_COUNTRY_ALLOWLIST, ICP_TITLE_ALLOWLIST, ICP_TITLE_DENYLIST), la instancia y el token de Salesforce, y los tres emails de los pools de SDR y handles de Slack. La lista completa y dónde encontrar cada valor está en _README.md. Cada variable tiene un fallback en el código para que el flujo nunca falle por una faltante —pero los valores por defecto son deliberadamente genéricos, así que configúralos antes de salir a producción.
Conecta las credenciales. Se requieren tres credenciales:
PLACEHOLDER_ANTHROPIC_CRED_ID — HTTP Header Auth con x-api-key seteado a tu clave de Anthropic
PLACEHOLDER_SLACK_CRED_ID — HTTP Header Auth con Authorization: Bearer xoxb-…
PLACEHOLDER_SALESFORCE_CRED_ID — HTTP Header Auth con Authorization: Bearer <sfdc_token> (o una credencial OAuth de Connected App para producción)
Apunta los webhooks a n8n. En Warmly, agrega tu URL https://<your-n8n-host>/webhook/visitor-deanon bajo Settings → Webhooks. En RB2B, usa la integración Webhook (o un “Catch Hook” de Zapier que reenvíe a la misma URL). No se almacena ninguna credencial en n8n para ninguno de los dos proveedores —ellos te empujan a ti.
Ajusta la rúbrica de ICP. Abre ICP Fit Gate y lee el bloque de puntuación. Otorga puntos por función del puesto, seniority, banda de tamaño de empresa, país e intención de página, y deja pasar a cualquiera que esté en o por encima de ICP_FIT_THRESHOLD (por defecto 3). Ajusta los pesos de los puntos y el umbral a tu definición de encaje antes de activarlo.
Verifica cada camino. Recorre la verificación en _README.md: publica un payload claramente dentro del ICP (debería pasar y redactar), un payload claramente fuera del ICP (debería descartarse en el gate), y el mismo payload dentro del ICP dos veces (el segundo debería descartarse en el dedup). Corre la prueba de dedup contra el webhook en vivo, no contra el botón Execute Workflow —los datos estáticos solo persisten en las corridas de producción.
Qué hace el flujo
Webhook — Visitor Deanon Ingest acepta solicitudes POST e inmediatamente devuelve 202 vía Respond 202 Accepted para que el llamador del webhook del proveedor no quede bloqueado esperando la llamada al LLM. Normalize Visitor Payload es un nodo Code que detecta la fuente por la forma del payload —RB2B (identificado por sus campos Business Email / Captured URL), Warmly (identificado por su anidamiento de contacto-más-empresa), y un fallback genérico— y mapea cada uno a un registro interno con campos consistentes: firstName, lastName, title, company, domain, email, linkedinUrl, employeeCount, industry, country, pageViewed, y referrer. El campo pageViewed viene del Captured URL de RB2B y del referrer de la señal de Warmly —es lo que hace que el borrador sea cálido en lugar de frío.
ICP Fit Gate es el nodo que distingue este flujo de un simple enrutador de intención. Puntúa a la persona contra una rúbrica: función del puesto contra una allowlist (revops, sales, marketing, growth, founder, product) y una denylist (student, intern, seeking, agency recruiter); seniority (C-level, VP, Head, Director puntúan más alto); banda de tamaño de empresa entre ICP_MIN_EMPLOYEES e ICP_MAX_EMPLOYEES; país contra ICP_COUNTRY_ALLOWLIST; e intención de página (una vista de /pricing, /demo o /product suma puntos). Si el total está por debajo de ICP_FIT_THRESHOLD, el nodo devuelve un arreglo vacío y la ejecución se detiene en silencio —la persona nunca llega a un rep. El fitScore y las razones se adjuntan al registro para que la tarjeta de Slack de un visitante que pasa muestre por qué calificó, y para que una rúbrica mal configurada sea auditable.
Dedup Gate (Static Data) usa los datos estáticos del workflow de n8n —$getWorkflowStaticData('global')— para guardar una clave por-persona-por-semana (dedup_<email-or-linkedin>_<ISO-week>). El nivel semanal es la ventana correcta para el outreach cálido: alguien que visita tu sitio tres veces en cinco días debería generar un contacto de rep, no tres. Ese objeto es la única forma correcta de persistir estado entre ejecuciones desde un nodo Code —la API REST pública de n8n no tiene un recurso de datos estáticos— y el nodo estampa la clave antes de cualquier llamada río abajo para que dos revelaciones concurrentes de la misma persona no puedan pasar ambas, y poda las claves de semanas anteriores para que el almacén se mantenga pequeño.
Salesforce — Contact Lookup consulta un Contact que coincida con el email de la persona, devolviendo el Contact Id, Account Id, Owner (Id, Name, Email, Slack_Handle__c), y dos señales de supresión: si la cuenta tiene una Opportunity abierta y si el contacto ya está en una secuencia activa (vía un campo Current_Sequence__c). Routing & Suppression Logic entonces decide. Si el contacto existe y hay cualquier señal de supresión seteada —oportunidad abierta, secuencia activa, o un tipo de cuenta de cliente existente— el nodo devuelve un arreglo vacío: un contacto cálido de desanonimización pisaría un movimiento en vivo, así que se descarta y se registra. De lo contrario, si el contacto existe, el spike se enruta al dueño de la cuenta y el flujo creará una Task sobre el contacto existente. Si no existe contacto —el caso común de desanonimización, ya que todo el sentido es sacar a la superficie a gente que aún no está en tu CRM— se enruta a un pool de SDR por territorio (AMER/EMEA/ROW por país) y el flujo creará un Lead. El nodo setea createSObject a Task o Lead según corresponda.
Claude — Draft Warm First Touch publica a la API de Anthropic con claude-haiku-4-5, un timeout de 8 segundos, y neverError: true. El system prompt prohíbe el relleno (“I noticed,” “reach out,” “touch base,” “circle back”) e instruye a Claude a anclar la apertura a la página específica vista y al rol de la persona —porque “vi que estabas en la página de precios” es accionable y “me encantaría conectar” no lo es. Parse Draft (with fallback) maneja un timeout o un JSON malformado produciendo un borrador basado en plantilla etiquetado draftSource: template-fallback; ambos caminos producen draftSubject, draftBody, y draftTalkingPoint. Slack — Notify Assignee publica una tarjeta de Block Kit en #visitor-deanon con el nombre, puesto, empresa, URL de LinkedIn de la persona, la página que vio, el fitScore y las razones, y el borrador etiquetado “edit before sending.” Salesforce — Create Record hace POST a /sobjects/{{ createSObject }} —un Lead para personas totalmente nuevas, una Task ligada al contacto existente vía WhatId en caso contrario— con OwnerId seteado solo a un Salesforce User Id real (nunca un email, que devuelve MALFORMED_ID) y omitido cuando se enruta a un pool.
Realidad de costos
Por cada visitante identificado que pasa el gate de ICP, claude-haiku-4-5 recibe aproximadamente 500 tokens de entrada y produce alrededor de 150 tokens de salida para el borrador de tres campos. Al precio de Haiku 4.5 (~$0.80/M entrada, ~$4/M salida) eso es cerca de $0.0007 por borrador. El gate de ICP hace la contención de costos: si el tier Pro de RB2B saca a la superficie ~1,000 visitantes identificados al mes y tu rúbrica deja pasar el 30%, redactas ~300 veces al mes —menos de $0.25/mes en gasto de Claude. La ventana de dedup significa que un visitante recurrente se factura una vez por semana, no por visita.
La herramienta de desanonimización es la verdadera partida, no la automatización. RB2B va de $159/mes (~250 visitantes identificados) a $499/mes (~1,000); los planes de pago de Warmly empiezan en $15,000/año y su suite completa de Autopilot es $30,000/año. n8n auto-hospedado es gratis; n8n Cloud Starter a $20/mes cubre 5,000 ejecuciones, manejando cómodamente ~300 visitantes redactados a ~9 nodos cada uno. El uso de la API de Salesforce es una consulta más una creación por visitante que pasa —unos pocos cientos de llamadas al mes contra un límite Enterprise de 15,000+/día. El bot de Slack y el endpoint de webhook de n8n son gratis.
Modos de falla
La rúbrica de ICP descarta a todos en silencio. Un umbral demasiado estricto o una allowlist de puestos que no considera cómo tus compradores realmente escriben sus títulos (p. ej. “RevOps” como substring de denylist atrapando accidentalmente “Revenue Operations”) significa que cada visitante falla el gate y el canal #visitor-deanon queda callado —lo que se lee como “no hay tráfico” cuando en realidad es “filtro mal configurado”. Salvaguarda: ICP Fit Gate adjunta fitScore y razones por regla a cada registro, y la verificación en _README.md incluye publicar un payload conocido dentro del ICP y confirmar que pasa. Vigila la tasa de aprobación durante la primera semana; si está cerca de cero en tráfico real, afloja la rúbrica.
Los datos estáticos de dedup persisten solo en corridas de producción.Dedup Gate (Static Data) lee y escribe $getWorkflowStaticData('global'), que n8n guarda solo cuando la ejecución se dispara en producción —nunca en una corrida manual de Execute Workflow. Probar el dedup haciendo clic en Execute Workflow dos veces hace que el gate parezca roto cuando está funcionando. Salvaguarda: activa el workflow y haz POST a la URL del webhook en vivo dos veces; el segundo POST debería descartarse en el dedup. El nodo poda las claves de la semana anterior en cada corrida, así que el almacén se auto-limpia.
El borrador se dirige a la persona equivocada. La desanonimización a nivel de persona es probabilística —la identificación de RB2B ronda un 50-70% de precisión en tráfico de ICP de EE. UU.— así que un borrador puede saludar a un nombre que no es realmente quien visitó. Salvaguarda: el flujo nunca envía. La tarjeta de Slack lidera con la URL de LinkedIn para que el SDR verifique la identidad en un clic antes de editar y enviar, y el borrador está etiquetado como un punto de partida tanto en el system prompt como en el mensaje de Slack.
La rotación del Bearer token de Salesforce atasca las consultas. Un Bearer token en crudo en SFDC_ACCESS_TOKEN rota (cada ~2 horas en orgs sin una política de sesión persistente). Cuando expira, Salesforce — Contact Lookup devuelve 401 en silencio (porque neverError: true), así que cada visitante parece totalmente nuevo y se enruta a un pool como Lead —saltándose silenciosamente la supresión. Salvaguarda: vigila si hay una racha de creaciones de Lead con cero creaciones de Task incluso cuando sabes que hay contactos existentes visitando; para producción, reemplaza el token en crudo por un Connected App usando el flujo OAuth 2.0 client-credentials. El _README.md cubre esto.
vs alternativas
vs Warmly Autopilot. El propio agente de Warmly puede calificar y agendar a partir de una visita, y si ya estás pagando el tier de $30,000/año y no corres Salesforce como fuente de verdad para la supresión, puede ser suficiente. No es la herramienta correcta si quieres que la lógica de ICP y las reglas de supresión sean legibles y auditables por tu equipo de ops, si corres RB2B junto con o en lugar de Warmly, o si quieres que el contacto sea un borrador editado por un rep en lugar de un envío autónomo. Este flujo te da las tres cosas a costo de n8n y funciona a través de ambos proveedores.
vs RB2B → Slack → triaje manual. El push nativo de Slack de RB2B es el status quo: cada persona identificada, sin filtro de ICP, sin conciencia del CRM. Es amigable con el tier gratuito y está bien a bajo volumen, pero a 1,000 identificaciones al mes el canal se vuelve ruido que los reps ignoran, y no hay salvaguarda contra pingear a un contacto que está a mitad de un trato. Este flujo filtra primero al ICP y suprime los movimientos activos, así que lo que aterriza en Slack vale la pena leerse.
vs un auto-enroll de Zapier hacia Instantly/Smartlead. El movimiento de un clic es RB2B/Warmly → Zapier → secuenciador frío. Envía lo más rápido y es el de mayor riesgo: sin verificación humana sobre una identidad probabilística, sin supresión contra oportunidades abiertas, y los envíos fríos a personas recién desanonimizadas son la forma más rápida de quemar un dominio de envío. Este flujo cambia esa velocidad por un borrador con un rep en el loop y supresión consciente del CRM.
vs una tabla de Clay sobre un feed de desanonimización.Clay puede jalar un feed de desanonimización, enriquecerlo, aplicar una rúbrica de ICP con columnas de fórmula, y empujar a un secuenciador —y encaja muy bien para corridas de prospección por lotes. No está orientado a eventos, así que siempre hay un lag de lote entre la visita y el contacto. Usa Clay para la capa semanal de enriquecimiento-y-prospección; usa este flujo para la respuesta en tiempo real, cuando-la-visita-aún-está-tibia.
# 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.