Módulo 1: Google Sheets

Mini-Proyecto: Actualizar una Hoja desde un Evento

Descripción de la cápsula

Llegó el momento de juntar todo. Las siete cápsulas anteriores fueron piezas; esta las arma en un workflow real y funcional.

El proyecto: un registro de leads inteligente. Cada vez que llega un lead (por un formulario, un webhook, lo que sea), el workflow revisa si ese lead ya existe en la hoja. Si es nuevo, lo agrega. Si ya existía, actualiza sus datos sin duplicarlo. Y todo queda registrado con fecha y formato limpio.

Es un proyecto pequeño pero completo: usa el patrón "buscar antes de actuar" (cápsula 03), las operaciones de escritura (04 y 05), el mapeo manual (06) y el diseño defensivo (07). Cuando lo termines, tendrás un workflow que puedes adaptar a decenas de casos reales: registro de clientes, control de inventario, log de pedidos.


Lo que vas a construir

Un workflow llamado Registro de Leads que:

  1. Recibe un lead (nombre, email, ciudad)
  2. Busca en la hoja si ese email ya existe
  3. Si no existe → agrega una fila nueva con estado "nuevo" y fecha de alta
  4. Si ya existe → actualiza sus datos y registra la fecha de último contacto
  5. Es idempotente: el mismo lead puede llegar 100 veces, siempre hay exactamente una fila

Lo que vas a practicar

  • ✅ El patrón "buscar antes de actuar" completo (lookup → IF → acción)
  • Update or Append vs el patrón explícito con IF — y por qué aquí usamos el explícito
  • Mapeo manual con transformación de datos
  • Diseño defensivo: valores por defecto, formato de fecha consistente
  • ✅ Construir un workflow que funciona con datos reales, no solo en la demo

Preparación: la hoja

Crea una hoja llamada Leads CRM con estas columnas en la fila 1:

emailnamecitystatussignup_datelast_contact_date

Déjala vacía de datos (solo encabezados). Formatea la columna email como Texto sin formato (cápsula 07).


Arquitectura del workflow

Trigger (Manual o Webhook)
   │
   ▼
Set: normalizar el lead que llega
   │
   ▼
Google Sheets: Get Row(s)  ──  filtro: email = {{ $json.email }}
   │
   ▼
IF: ¿el lookup devolvió 0 items?
   │
   ┌──────────────┴──────────────┐
   ▼ TRUE (no existe)            ▼ FALSE (ya existe)
Google Sheets: Append Row     Google Sheets: Update Row
(lead nuevo + signup_date)    (actualiza + last_contact_date)

¿Por qué no usar Update or Append y ya? Porque queremos hacer algo distinto según el caso: a un lead nuevo le ponemos signup_date, a uno existente le ponemos last_contact_date. Como la lógica difiere (no solo el contenido), usamos el patrón explícito con IF — exactamente la última fila de la tabla de decisión de la cápsula 05.


Paso 1: El trigger y los datos de entrada

Para desarrollar, usa un Manual Trigger seguido de un Set que simula el lead que llega:

Nodo Set (modo manual, crea estos campos):

name   = Ana López
email  = ANA@example.com
city   = CDMX

Nota el email con mayúsculas a propósito — lo normalizamos en el siguiente paso. En producción, este Set se reemplaza por un Webhook Trigger que recibe el lead real de un formulario. El resto del workflow no cambia.


Paso 2: Normalizar el lead

Agrega otro nodo Set (o usa el mismo) para limpiar los datos antes de tocarlos. Esto es diseño defensivo de la cápsula 06:

email  = {{ $json.email.toLowerCase().trim() }}
name   = {{ $json.name.trim() }}
city   = {{ $json.city || 'Sin especificar' }}

Ahora el email siempre está en minúsculas y sin espacios — clave para que el lookup del siguiente paso encuentre coincidencias de verdad.


Paso 3: El lookup

Agrega un nodo Google Sheets:

  • Operation: Get Row(s)
  • Document: Leads CRM
  • Sheet: la pestaña
  • Filters → Add Filter:
    • Column: email
    • Value: {{ $json.email }}

Renombra este nodo a Find Lead (click derecho → Rename). Lo vamos a referenciar por nombre en el IF.

Este nodo devuelve los items que coinciden — 0 si el lead es nuevo, 1 (o más) si ya existía.


Paso 4: El IF — ¿existe o no?

Agrega un nodo IF después de Find Lead:

  • Condition (modo expression):
{{ $('Find Lead').all().length === 0 }}
  • true → el lookup no encontró nada → lead nuevo
  • false → el lookup encontró algo → lead existente

Ojo importante: el IF debe seguir teniendo acceso al lead normalizado (el del paso 2), no al output del lookup. Por eso referenciamos $('Find Lead') para contar resultados, pero los datos del lead los tomamos del Set. Si te enredas, agrega un nodo Merge o referencia explícita con $('Set') en los nodos siguientes.


Paso 5: Rama TRUE — agregar lead nuevo

En la salida true del IF, un nodo Google Sheets:

  • Operation: Append Row
  • Document: Leads CRM
  • Sheet: la pestaña
  • Mapping: manual
    • email{{ $('Set').item.json.email }}
    • name{{ $('Set').item.json.name }}
    • city{{ $('Set').item.json.city }}
    • statusnew (texto fijo)
    • signup_date{{ $now.toFormat('yyyy-LL-dd') }}
    • last_contact_date{{ $now.toFormat('yyyy-LL-dd') }}

(Reemplaza 'Set' con el nombre real de tu nodo de normalización.)


Paso 6: Rama FALSE — actualizar lead existente

En la salida false del IF, otro nodo Google Sheets:

  • Operation: Update Row
  • Document: Leads CRM
  • Sheet: la pestaña
  • Column to match on: email
  • Mapping: manual — solo las columnas que cambian
    • email{{ $('Set').item.json.email }} (la clave de match)
    • name{{ $('Set').item.json.name }} (por si actualizó su nombre)
    • city{{ $('Set').item.json.city }} (por si cambió de ciudad)
    • last_contact_date{{ $now.toFormat('yyyy-LL-dd') }}

Nota qué no mapeamos: status y signup_date. Un lead existente conserva su estado y su fecha de alta original — son datos que no queremos pisar (cápsula 05: Update es quirúrgico).


Paso 7: Probar el workflow

Aquí compruebas que es idempotente:

Prueba 1: lead nuevo

  1. Ejecuta el workflow con Ana López / ANA@example.com / CDMX
  2. Mira la hoja: una fila nueva, status = new, ambas fechas de hoy

Prueba 2: el mismo lead otra vez

  1. Ejecuta otra vez, sin cambiar nada
  2. Mira la hoja: sigue habiendo una sola fila de Ana. No se duplicó. Se actualizó last_contact_date

Prueba 3: el mismo lead con datos cambiados

  1. Cambia el Set: Ana López / ANA@example.com / Guadalajara
  2. Ejecuta
  3. Mira la hoja: una sola fila, city ahora es Guadalajara, status sigue siendo new, signup_date no cambió

Prueba 4: un lead diferente

  1. Cambia el Set: Beto Ruiz / beto@example.com / Lima
  2. Ejecuta
  3. Mira la hoja: ahora hay dos filas — Ana y Beto

Si las cuatro pruebas dan el resultado esperado: el workflow es correcto e idempotente. Felicidades.


Checklist de éxito

  • Un lead nuevo se agrega con status = new y signup_date
  • El mismo lead repetido no se duplica — se actualiza
  • Al actualizar, status y signup_date no se pisan
  • Al actualizar, last_contact_date se refresca
  • El email se guarda siempre en minúsculas (normalización funcionando)
  • Un lead distinto crea su propia fila
  • Las fechas se ven como 2026-05-14, no como objetos raros

Cómo llevar esto a producción

Lo que construiste es un esqueleto reutilizable. Para producción:

  • Cambia el Manual Trigger por un Webhook Trigger — el formulario manda el lead directo. El resto del workflow no cambia.
  • Conecta el formulario real: Google Forms, Typeform, un formulario de tu web — todos pueden mandar a un webhook.
  • Agrega notificaciones: en la rama TRUE (lead nuevo), podrías agregar un nodo que avisa al equipo de ventas. Eso conecta con el Módulo 4 (Slack) y Módulo 2 (Gmail) de esta guía.
  • Maneja errores: si Google Sheets falla, ahora mismo el workflow se detiene. G10 (Production) cubre cómo hacerlo resiliente.

Variaciones del mismo patrón

Este workflow es el patrón base para muchísimos casos. Cambia los nombres y tienes:

CasoColumna clave"Nuevo" hace..."Existe" hace...
Registro de leadsemailagrega leadactualiza datos
Control de inventarioskucrea productoajusta stock
Log de pedidosorder_idregistra pedidoactualiza estado de envío
Lista de suscriptoresemailsuscribere-suscribe / actualiza preferencias

El esqueleto es idéntico. Lo único que cambia es la columna clave y qué se escribe en cada rama.


Resumen del módulo

Con este proyecto cierras el Módulo 1 — Google Sheets. Recapitulando lo que ahora dominas:

  • Conectar Google Sheets con OAuth2 (cápsula 02)
  • Leer y buscar filas con lookup (cápsula 03)
  • Agregar filas con Append sin duplicar (cápsula 04)
  • Actualizar filas existentes y usar upsert (cápsula 05)
  • Mapear datos entre tu workflow y la hoja, con transformación (cápsula 06)
  • Diagnosticar rate limits, formatos y permisos (cápsula 07)
  • Integrar todo en un workflow idempotente y reutilizable (esta cápsula)

El patrón estrella de todo el módulo: buscar antes de actuar. Es lo que separa un workflow que duplica basura de uno que mantiene tus datos limpios.

Lo que sigue (Módulo 2):

Google Sheets guarda datos. El Módulo 2 — Gmail y email los pone en movimiento: enviar correos automáticos, recibir y filtrar emails entrantes, etiquetar, y construir respuestas automáticas. Vas a poder cerrar el círculo: un lead entra a la hoja (M01) y recibe un email de bienvenida (M02).


Recursos adicionales

  1. n8n Google Sheets node Docs - Referencia completa del nodo.
  2. n8n Webhook Trigger Docs - Para llevar el proyecto a producción.
  3. n8n IF node Docs - El nodo que decide entre las dos ramas.

Creado: Mayo 14, 2026 Versión: 1.0