SteerAds
Google AdsTutorielOptimisation

n8n Google Ads: 5 flujos de automatización 2026

n8n self-hosted (open-source, gratuito) para automatizar Google Ads: monitoring CPC, alertas Slack, sync GA4, reporting semanal, push offline conversions CRM. Aquí tienes 6 workflows JSON listos para importar, más el docker-compose para alojar n8n en 10 minutos.

Matt
MattTracking & Data Lead
···10 min de lectura

n8n ha superado los 100.000 deployments self-hosted activos en 2025 (n8n.io) y 70.000 stars GitHub en Q1 2026, convirtiéndose en la alternativa open-source dominante a Zapier y Make. El criterio económico es masivo: un workflow Zapier que se ejecuta 10.000 veces al mes cuesta aproximadamente 89 EUR/mes en plan Professional, el mismo workflow en n8n self-hosted cuesta 0 EUR más allá de los 8 a 15 EUR/mes de VPS. En las cuentas observadas en los benchmarks públicos de Google Ads, las estructuras que pasan a n8n recuperan 600 a 1.800 EUR/mes en el concepto de automatización, es decir el ROI más rápido de todo el stack de herramientas.

Aquí exactamente el setup self-hosted, las credentials Google Ads, y 6 workflows JSON listos para importar para automatizar el pilotaje de Google Ads. Nada de generalidades "n8n es genial" — contenido concreto con docker-compose, exports JSON, snippets de transformación. El repo github.com/steerads/n8n-google-ads-flows contiene los 6 workflows documentados. Si aún estás comparando con Zapier y Make, lee en paralelo nuestro comparativo Zapier vs Make Google Ads. Nuestro calculador de gasto desperdiciado estima los EUR quemados/mes por broad sin negativos o bounce rate excesivo en LP.

n8n vs Zapier/Make: por qué self-hosted para Google Ads

n8n es una herramienta de workflow automation low-code open-source lanzada en 2019. Editor visual drag-drop similar a Zapier o Make, pero con dos diferencias clave: (1) self-hosted posible bajo licencia Sustainable Use License, (2) sin pricing por ejecución en la versión self-hosted. Pagas tu VPS, punto.

El cálculo económico a 12 meses para una cuenta que ejecuta 50 workflows activos (hourly + daily mix):

Cuándo n8n self-hosted gana: volumen elevado de ejecuciones (>5.000/mes), workflows complejos con JavaScript inline, integraciones custom no cubiertas por los SaaS, restricciones de data residency (RGPD estricto, datos sensibles), equipos técnicos que pueden mantener Docker.

Cuándo Zapier/Make siguen siendo superiores: equipos no técnicos (cero ops infra), workflows simples de bajo volumen (<1.000 ejecuciones/mes), arranque muy rápido (15 min Zapier vs 1h n8n), necesidad de integraciones exóticas (Zapier tiene 5.000+ apps nativas vs ~400 en n8n).

Para el específico Google Ads, n8n tiene una ventaja clave: sin cuota por ejecución, por lo que puedes ejecutar un workflow hourly de monitoring CPC durante 1 año sin pagar 1 EUR más que el VPS. En Zapier, ese mismo workflow te cuesta 8.760 ejecuciones x ~$0.02 = ~$175 mínimo al año.

Tres patrones de despliegue coexisten en 2026 según el perfil de equipo y las restricciones de infra. Patrón 1 — Docker Compose en VPS único (el más extendido): un solo VPS Hetzner o DigitalOcean a 5-12 EUR/mes, n8n + Postgres + Caddy en compose, snapshots automáticos cada 24 horas del lado del proveedor. Recomendado para el 90% de los casos de uso SMB y mid-market. Patrón 2 — n8n Cloud managed (n8n.cloud): desde 20 EUR/mes según el plan, cero ops de infra a gestionar, ideal si el equipo no quiere tocar Docker en absoluto. El compromiso: sin personalización del entorno runtime, y los datos no se quedan en tu servidor. Patrón 3 — Kubernetes para multi-tenant o muy alta disponibilidad: despliegue Helm chart oficial n8n en GKE/EKS/AKS, pertinente únicamente para agencias que mutualizan varios clientes o setups SaaS internos de muy alta carga. Cuenta con 80 a 250 EUR/mes según el tamaño del cluster.

La elección Docker Compose vs n8n Cloud merece resolverse al inicio. Docker Compose da el 100% de control (datos en tu servidor, entorno custom, latencia de red mínima hacia Postgres), pero requiere una disciplina ops mínima: updates Docker cada 1-2 meses, monitoreo del espacio en disco (la tabla executions crece rápido), gestión del certificado Let's Encrypt si Caddy falla. n8n Cloud elimina toda esa carga pero introduce una dependencia externa y un coste fijo que escala linealmente con el número de workflows activos. Para un equipo data con 1 solo DevOps a tiempo parcial, Docker Compose sigue siendo la opción por defecto. Para un equipo de marketing puro sin operaciones técnicas, n8n Cloud evita semanas de deuda técnica.

Setup n8n: Docker, credentials, primer workflow

El setup más rápido para alojar n8n en producción: Docker Compose en un VPS Ubuntu con Caddy como reverse proxy (HTTPS automático vía Let's Encrypt). Aquí exactamente el docker-compose.yml a pegar:

# docker-compose.yml — n8n self-hosted production-ready
version: "3.8"

services:
  caddy:
    image: caddy:2
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    networks:
      - n8n-network

  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: n8n
    volumes:
      - postgres_data:/var/lib/postgresql/data
    networks:
      - n8n-network

  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    restart: unless-stopped
    environment:
      - DB_TYPE=postgresdb
      - DB_POSTGRESDB_HOST=postgres
      - DB_POSTGRESDB_DATABASE=n8n
      - DB_POSTGRESDB_USER=n8n
      - DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
      - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
      - N8N_HOST=n8n.tudominio.com
      - N8N_PROTOCOL=https
      - WEBHOOK_URL=https://n8n.tudominio.com/
      - GENERIC_TIMEZONE=Europe/Madrid
      - EXECUTIONS_DATA_PRUNE=true
      - EXECUTIONS_DATA_MAX_AGE=336
    volumes:
      - n8n_data:/home/node/.n8n
    depends_on:
      - postgres
    networks:
      - n8n-network

volumes:
  postgres_data:
  n8n_data:
  caddy_data:
  caddy_config:

networks:
  n8n-network:

El Caddyfile correspondiente para el reverse proxy HTTPS automático:

n8n.tudominio.com {
    reverse_proxy n8n:5678
    encode gzip
}

El .env a colocar al lado (NO hacer commit):

POSTGRES_PASSWORD=un_password_fuerte_minimo_32_chars_xxxxxx
N8N_ENCRYPTION_KEY=encryption_key_32_chars_estricto_yyyyyyyy

Generar la N8N_ENCRYPTION_KEY con openssl rand -hex 32. Esta clave cifra todas las credentials almacenadas por n8n (OAuth tokens, API keys) — si la pierdes, todas las credentials son irrecuperables.

Lanzamiento:

# DNS prerrequisito: apuntar n8n.tudominio.com hacia la IP del VPS
docker-compose up -d
docker-compose logs -f n8n  # verificar el arranque

n8n es accesible en https://n8n.tudominio.com tras ~2 minutos (tiempo de Caddy para generar el certificado Let's Encrypt). Primer acceso: crear una cuenta admin, definir la timezone, y listo.

Estrategia de backup para credentials y workflows

Una vez n8n en producción, la pérdida de las credentials cifradas o de la base Postgres puede costar semanas de reconfiguración. Tres ejes de backup a implementar imperativamente antes de migrar tus workflows críticos. Eje 1 — Snapshot de disco del lado del proveedor. Activar los snapshots automáticos diarios en el VPS (1-2 EUR/mes adicionales en Hetzner o DigitalOcean). En caso de corrupción o mala manipulación, restauración en menos de 10 minutos a un punto del historial. Es la red de seguridad más barata y eficaz, que no requiere ninguna lógica aplicativa.

Eje 2 — Dump Postgres regular y cifrado. Cron diario que ejecuta pg_dump n8n luego cifra el dump con age o GPG, luego push en un bucket S3-compatible (R2 Cloudflare, Backblaze B2, Wasabi) con retención 30 días. La lógica de cifrado es esencial: el dump contiene todos los workflows pero también las credentials de Google Ads cifradas con tu encryption_key. Si el dump se filtra en claro sin cifrado, cualquiera que tenga la encryption_key puede acceder a tus credentials. Almacenar la encryption_key por separado del dump (idealmente en un password manager compartido con el admin de backup del equipo).

Eje 3 — Export JSON de los workflows críticos en source control. Para cada workflow de producción, exportar el JSON vía "Download" en la UI de n8n y hacer commit en un repo Git privado dedicado. Esto da dos beneficios: versionado y code review de los cambios de workflow, y restauración inmediata si la base Postgres se pierde. La encryption_key sigue siendo necesaria para reimportar con credentials, pero la estructura del workflow se preserva. En las cuentas observadas en los benchmarks públicos de Google Ads, los equipos que combinan los tres ejes nunca pierden más de 24 horas de configuración en caso de incidente, frente a semanas para los que solo tienen un eje.

Configurar las credentials Google Ads

En Credentials > Add Credential > Google Ads OAuth2 API. Rellenar:

  • Client ID: desde tu proyecto GCP (consulta nuestra guía API Python setup para el procedimiento de generación).
  • Client Secret: ídem.
  • Scope: https://www.googleapis.com/auth/adwords.
  • Authorization URL: pre-rellenado por n8n.
  • Token URL: pre-rellenado.
  • Redirect URL: copiar el valor proporcionado por n8n y añadirlo a los Authorized redirect URIs de tu OAuth client en la GCP Console.

Clicar Connect my account, validar en la ventana OAuth, n8n recupera automáticamente el refresh_token y lo almacena cifrado.

Para el developer_token (que no está en el OAuth), añadir una Credential separada Header Auth con Header Name: developer-token y Header Value: YOUR_DEVELOPER_TOKEN. Los nodes HTTP Request que llaman a la API Google Ads consumirán este header.

Flow 1-2: monitoring CPC + alertas Slack

Los 2 primeros flows cubren el monitoring diario: detectar las anomalías de CPC y alertar en Slack. Es el caso de uso más rentable al inicio.

Flow 1 — Monitoring CPC con alertas Slack

Trigger: Cron, every hour. Lógica: pull los CPC medios de las campañas ENABLED en las últimas 24h deslizantes, comparar con el CPC medio a 7 días, alerta Slack si variación > +25%.

El workflow JSON exportado (extracto minificado para lectura):

{
  "name": "GoogleAds — CPC Monitoring + Slack Alerts",
  "nodes": [
    {
      "name": "Cron Hourly",
      "type": "n8n-nodes-base.cron",
      "parameters": {
        "triggerTimes": { "item": [{ "mode": "everyHour" }] }
      }
    },
    {
      "name": "Pull GAQL CPC",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "POST",
        "url": "https://googleads.googleapis.com/v17/customers/{{$env.CUSTOMER_ID}}/googleAds:search",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleAdsOAuth2Api",
        "headerParameters": {
          "parameters": [
            { "name": "developer-token", "value": "{{$env.DEV_TOKEN}}" },
            { "name": "login-customer-id", "value": "{{$env.LOGIN_CID}}" }
          ]
        },
        "bodyParameters": {
          "parameters": [
            {
              "name": "query",
              "value": "SELECT campaign.id, campaign.name, metrics.average_cpc FROM campaign WHERE campaign.status = 'ENABLED' AND segments.date DURING LAST_7_DAYS"
            }
          ]
        }
      }
    },
    {
      "name": "Compute Variations",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "language": "javaScript",
        "jsCode": "const items = $input.all();\nconst alerts = [];\nfor (const i of items) {\n  const c = i.json;\n  // Calcul variation CPC vs baseline\n  const cpcNow = c.metrics.average_cpc / 1000000;\n  const cpcAvg7d = c.baseline_cpc;\n  const variation = (cpcNow - cpcAvg7d) / cpcAvg7d;\n  if (variation > 0.25) {\n    alerts.push({\n      campaign: c.campaign.name,\n      cpc_now: cpcNow.toFixed(2),\n      cpc_baseline: cpcAvg7d.toFixed(2),\n      variation_pct: (variation * 100).toFixed(1)\n    });\n  }\n}\nreturn alerts.map(a => ({ json: a }));"
      }
    },
    {
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#google-ads-alerts",
        "text": "[CPC ALERT] {{$json.campaign}} - CPC +{{$json.variation_pct}}% ({{$json.cpc_baseline}} EUR -> {{$json.cpc_now}} EUR)"
      }
    }
  ]
}

Variables a customizar tras importar: CUSTOMER_ID (10 dígitos cuenta cliente), DEV_TOKEN (developer token Google Ads), LOGIN_CID (MCC padre), Slack channel.

Frecuencia del trigger: every hour durante las horas de negocio, daily por la noche (evitar falsos positivos en bajo volumen). Output: un mensaje Slack por campaña cuyo CPC supera +25% del baseline.

Flow 2 — Detección anomalías spend (>2x avg 7d)

Trigger: Cron, every 4 hours. Lógica: pull spend total de la cuenta en el periodo deslizante, comparar con la media 7 días x factor. Si variación superior a 2x, alertar en Slack con breakdown por campaña.

El patrón n8n es similar al Flow 1, con 4 nodes:

  1. Cron every 4h.
  2. HTTP Request GAQL: pull spend total + breakdown por campaign.
  3. Code: cálculo variación vs baseline 7d, identificación de las campañas causantes.
  4. Slack: envío mensaje estructurado si hay anomalía.

Las variables a ajustar: SPEND_VARIATION_THRESHOLD (2.0 = +100% = el doble), MIN_SPEND_BASELINE (filtrar las campañas de bajo volumen para evitar falsos positivos), ALERT_CHANNEL.

Tip dev anti-falsos positivos :

Siempre filtrar las campañas de bajo volumen antes de la comparación (ej.: skip si spend baseline inferior a 50 EUR). En una cuenta con 30 campañas de las cuales 20 son micro-campañas a 5-10 EUR/día, sin filtro spameas Slack con 15 alertas/día. El ratio señal/ruido cae, el equipo ignora las alertas, y te pierdes las verdaderas anomalías.

Flow 3-4: sync conversiones CRM hacia Google Ads

Los flows 3-4 cubren el push de conversiones offline desde un CRM hacia Google Ads (Offline Conversion Imports + Customer Match). Es uno de los casos de uso más rentables para los SaaS B2B y el lead gen con ciclo de venta largo.

Flow 3 — Push HubSpot deals won hacia Google Ads offline conversions

Trigger: webhook HubSpot (deal stage = closed-won). Lógica: recibir el webhook, recuperar el gclid del deal (almacenado en una custom property), formatear el payload según la spec Google Ads UploadClickConversion, push hacia la API.

Arquitectura del flow:

[Webhook HubSpot] -> [Extract GCLID + value] -> [Format payload Google Ads]
                                              -> [HTTP POST UploadClickConversion]
                                              -> [Log success/error in PostgreSQL]
                                              -> [Slack notify if error]

El node HTTP Request hacia Google Ads Offline Conversion:

// Code node: format payload
const dealData = $input.first().json;
const gclid = dealData.properties.hs_gclid;
const dealValue = parseFloat(dealData.properties.amount);
const closeDate = dealData.properties.closedate;

if (!gclid) {
  // Sin GCLID = no trackeable (deal orgánico o fuente no-Google)
  return [{ json: { skip: true, reason: "no_gclid" } }];
}

// Formato ISO requerido por Google Ads
const conversionDateTime = new Date(closeDate)
  .toISOString()
  .replace("T", " ")
  .substring(0, 19) + "+00:00";

return [{
  json: {
    conversions: [{
      gclid,
      conversion_action: `customers/${$env.CUSTOMER_ID}/conversionActions/${$env.CONV_ACTION_ID}`,
      conversion_date_time: conversionDateTime,
      conversion_value: dealValue,
      currency_code: "EUR"
    }],
    partial_failure: true,
    validate_only: false
  }
}];

Variables a customizar: CUSTOMER_ID, CONV_ACTION_ID (el ID de la conversion action "Closed Deal" creada previamente en la UI de Google Ads). Consulta nuestra guía conversion tracking Google Ads para la creación de la conversion action y el marco funcional de offline imports.

Trampas críticas:

  • El GCLID expira 90 días después del clic. Si tu ciclo de venta supera los 90 días, el push debe hacerse antes de la expiración o usar GBRAID/WBRAID para iOS.
  • El deal value debe estar en la moneda nativa de la cuenta (EUR, USD, GBP). Sin mezclar.
  • partial_failure: true permite a Google aceptar las conversiones válidas incluso si una sola del batch es inválida. Sin este flag, un error hace rechazar todo el batch.

Flow 4 — Sync GA4 audiences hacia Customer Match

Trigger: Cron daily 3am. Lógica: query una audiencia GA4 (ej.: "users que han hecho pricing_page_view sin purchase"), recuperar los emails, hash en SHA-256, push hacia Google Ads Customer Match list.

El flow encadena 4 nodes principales: GA4 Data API pull -> SHA-256 hash node (custom Code) -> Google Ads OfflineUserDataJobService -> Slack confirm. Consulta nuestra guía Customer Match first-party data para la estrategia de audiencia completa.

Flow 5-6: reporting semanal email + Looker Studio

Los 2 últimos flows cubren el reporting recurrente: email semanal con KPI síntesis, y push BigQuery + refresh Looker Studio para los dashboards.

Flow 5 — Weekly performance report email HTML

Trigger: Cron, every Monday 8am. Lógica: pull KPI clave de los últimos 7 días (spend, clicks, conv, CPA, ROAS) por campaña, formatear un HTML email, enviar vía SMTP a la lista de difusión. Nuestro calculador CPA en 2 inputs devuelve el valor + mediana para tu vertical.

El Code node central que formatea el HTML:

// Format HTML weekly report
const campaigns = $input.all().map(i => i.json);

let html = `
<h2 style="font-family: Arial; color: #1a202c;" data-speakable>
  Google Ads Weekly Report - Week ${getWeekNumber()}
</h2>
<p>Period: ${getDateRangeLabel()}</p>
<table border="1" cellpadding="10" style="border-collapse:collapse; font-family:Arial; font-size:13px;">
  <tr style="background:#f5f5f5;">
    <th>Campaign</th><th>Spend</th><th>Clicks</th><th>Conv</th><th>CPA</th><th>ROAS</th>
  </tr>
`;

let totalSpend = 0, totalConv = 0;
for (const c of campaigns) {
  const cpa = c.conversions > 0 ? (c.cost_eur / c.conversions).toFixed(2) : "N/A";
  const roas = c.cost_eur > 0 ? (c.conversions_value / c.cost_eur).toFixed(2) : "N/A";
  html += `
    <tr>
      <td>${c.name}</td>
      <td>${c.cost_eur.toFixed(2)} EUR</td>
      <td>${c.clicks}</td>
      <td>${c.conversions.toFixed(1)}</td>
      <td>${cpa} EUR</td>
      <td>${roas}</td>
    </tr>
  `;
  totalSpend += c.cost_eur;
  totalConv += c.conversions;
}

html += `
</table>
<p><strong>Total Spend:</strong> ${totalSpend.toFixed(2)} EUR</p>
<p><strong>Total Conversions:</strong> ${totalConv.toFixed(1)}</p>
<p><strong>Avg CPA:</strong> ${(totalSpend / totalConv).toFixed(2)} EUR</p>
`;

function getWeekNumber() {
  const now = new Date();
  const start = new Date(now.getFullYear(), 0, 1);
  const days = Math.floor((now - start) / 86400000);
  return Math.ceil((days + start.getDay() + 1) / 7);
}

function getDateRangeLabel() {
  const end = new Date();
  const start = new Date();
  start.setDate(end.getDate() - 7);
  return `${start.toISOString().split("T")[0]} -> ${end.toISOString().split("T")[0]}`;
}

return [{ json: { html_body: html, subject: `Google Ads Report W${getWeekNumber()}` } }];

Variables: EMAIL_RECIPIENTS (lista separada por comas), SMTP_* (host, port, user, pass — credentials n8n SMTP).

Flow 6 — Daily push BigQuery + refresh Looker Studio

Trigger: Cron daily 4am. Lógica: pull todos los KPI granulares (por campaña, por keyword, por device, por geo) de las últimas 24h, push en append en una tabla BigQuery, trigger un refresh del dashboard Looker Studio vía webhook.

Es el patrón data warehousing clásico: BigQuery como single source of truth, Looker Studio (anteriormente Data Studio) como capa de visualización, n8n como orquestador ETL. Ventaja vs script Python: cero infra de scheduler a mantener, observabilidad nativa en n8n.

Buenas prácticas: error handling, retry, logging

Un workflow n8n que funciona 24/7 sin error handling cae en silencio y descubres el problema 3 semanas después cuando un cliente pregunta por qué el report ya no llega. 4 patrones críticos.

Patrón 1 — Error workflow dedicado. En Settings > Error Workflow, designar un workflow específico que se dispara cuando cualquier otro workflow falla. El error workflow recibe el payload del error (workflow name, node, error message, timestamp) y envía una alerta Slack. Todos los workflows de producción deben apuntar a este error workflow.

Patrón 2 — Retry on failure. En cada node crítico (HTTP Request especialmente), activar Retry On Fail con 3 retries y un delay de 30s. Para los errores transitorios (rate limit, timeout de red), el retry basta. Para los errores permanentes (auth expired, invalid argument), el node falla tras 3 intentos y el error workflow se activa.

Patrón 3 — Continue On Fail estratégico. Para los workflows que procesan N items en paralelo (ej.: push 100 conversiones HubSpot hacia Google Ads), activar Continue On Fail en el node de mutación. El workflow continúa incluso si 5 items fallan de 100. Añadir un node IF después para separar los success de los errors y loguear los errors en un node Postgres dedicado.

Patrón 4 — Pruning de ejecuciones históricas. En el .env Docker, configurar EXECUTIONS_DATA_MAX_AGE=336 (336 horas = 14 días) para purgar automáticamente las ejecuciones históricas. De lo contrario la DB n8n crece indefinidamente. Para 50 workflows activos con 100 ejecuciones/día cada uno, cuenta con ~150k rows en 14 días.

// Code node: log estructurado para observabilidad
const ts = new Date().toISOString();
const workflowName = $workflow.name;
const executionId = $execution.id;
const nodeOutput = $input.first().json;

return [{
  json: {
    log_level: "INFO",
    timestamp: ts,
    workflow: workflowName,
    execution_id: executionId,
    event: "workflow_completed",
    items_processed: $input.all().length,
    metadata: nodeOutput
  }
}];
Refresh token Google Ads :

Los refresh_token de Google Ads pueden ser revocados tras 90 días de inactividad o si Google detecta un comportamiento sospechoso (cambio de password de la cuenta, login desde nuevo device). Si tu workflow cae en INVALID_GRANT, regenerar el refresh_token vía el procedimiento OAuth y actualizarlo en n8n Credentials. Implementar una alerta Slack específica para este código de error para no descubrirlo 3 días después.

Límites de n8n vs API directa

n8n es un excelente compromiso low-code, pero tiene sus límites. 4 casos donde pasar a un script Python o Node.js standalone (consulta nuestra guía setup API Google Ads Python) sigue siendo superior.

Límite 1 — Muy alto volumen (>500k operaciones/día). n8n destaca en volúmenes moderados (1.000 a 100.000 ops/día). Más allá, la latencia por node + el overhead de escritura en DB ralentiza. Un script Python con batch operations nativas procesa 1M ops en 1h, vs 4-6h en n8n.

Límite 2 — Lógica algorítmica compleja. Para workflows que requieren ML inference, regresiones estadísticas, clustering — el Code node de n8n permite JS pero con un entorno restringido. Un script Python con scikit-learn / XGBoost sigue siendo más práctico.

Límite 3 — Integración producto. Si integras Google Ads en un producto interno (dashboard, app SaaS), n8n es demasiado "herramienta interna" y demasiado pesado. API directa vía SDK sigue siendo la opción correcta.

Límite 4 — Debugging en caliente en prod. n8n ofrece una observabilidad correcta pero no óptima (sin stacktrace completo en los nodes Code, logs limitados). Para un stack maduro, Python con un setup logging + Sentry supera a n8n en debugging UX.

Para el 80% de los casos de uso Google Ads de una SMB o mid-market (monitoring, sync CRM, reporting, alerting), n8n es ampliamente suficiente y el ratio coste/mantenimiento sigue siendo imbatible. Para las cuentas que quieren industrializar sin ops de infra, nuestro módulo Auto-optimización cubre los 6 flows anteriores en modo managed (cero VPS a mantener, cero refresh_token a renovar), con dashboard y alerting nativo. Consulta también nuestra checklist de auditoría Google Ads, nuestra guía de los 10 scripts Google Ads, nuestro comparativo Zapier vs Make para las opciones no-code, y nuestra guía MCP Google Ads Claude Desktop para la capa conversacional.

Errores comunes a evitar en producción n8n

Cinco errores vuelven de forma recurrente en los setups n8n self-hosted observados en auditoría. Cada uno puede costar varios días de incidente silencioso o malas decisiones en Google Ads basadas en datos incompletos. Aquí las trampas y cómo evitarlas.

1. Sin monitoring del propio workflow. Diagnóstico: el workflow cae en error tras un update de la API Google Ads o un refresh_token revocado, pero nadie se da cuenta hasta que un cliente pregunta por qué el report semanal ya no llega. Corrección: configurar un Error Workflow global que poste en Slack #ops-alerts con cada fallo, y un cron de heartbeat (workflow trivial que postea un OK diario) para detectar los casos donde el propio scheduler n8n está caído. Un workflow crítico sin heartbeat es un agujero de monitoring que puede durar semanas.

2. Almacenar la encryption_key en el mismo repo Git que el compose. Diagnóstico: el .env con N8N_ENCRYPTION_KEY se commitea por accidente, el atacante que clone el repo puede descifrar todas las credentials de Google Ads. Corrección: NUNCA hacer commit del .env. Usar un secret manager (Doppler, Vault, AWS SM, GCP Secret Manager) o como mínimo almacenar la clave en un password manager compartido con acceso de auditoría. Si la clave ya fue commiteada públicamente, regenerar inmediatamente y reconfigurar todas las credentials.

3. Workflows activos en la cuenta de test con login_customer_id de prod. Diagnóstico: un developer copia un workflow desde la cuenta de test hacia prod sin cambiar el login_customer_id, el workflow modifica presupuestos en la cuenta equivocada. Corrección: usar variables de entorno distintas por entorno (CUSTOMER_ID_TEST, CUSTOMER_ID_PROD) y una convención de naming estricta (workflow taggeado [PROD] o [TEST] en su nombre). Testear sistemáticamente en modo "Execute Workflow" sobre cuenta de test antes de activar en prod.

4. Base de datos Postgres que se satura sin purga de ejecuciones. Diagnóstico: tras 6 meses en prod, la base Postgres alcanza 50+ GB, los workflows se ralentizan, los backups tardan horas. Corrección: configurar EXECUTIONS_DATA_PRUNE=true y EXECUTIONS_DATA_MAX_AGE=336 (14 días) desde el setup. Para los workflows críticos cuyo log quieres conservar más tiempo, exportar hacia BigQuery o un datastore separado en el momento de la ejecución en lugar de inflar la DB n8n.

5. Bucle sin throttling en batchs de mutaciones Google Ads. Diagnóstico: un workflow que sincroniza 5.000 Customer Match emails falla en RESOURCE_EXHAUSTED porque llama a la API en paralelo sobre todos los items. Corrección: añadir un node "SplitInBatches" con batch_size 100 y un node "Wait" de 2 segundos entre batches. El throughput total se reduce ligeramente pero la tasa de error pasa del 30-40% a menos del 1%. Esta lógica vale para todas las batch operations hacia Google Ads, HubSpot, Salesforce, y otras APIs con rate limit.

Para los recursos oficiales, consulta la documentación de n8n (excelente nivel de detalle) y el repo oficial GitHub n8n para seguir los releases.

Fuentes

Fuentes oficiales consultadas para esta guía:

FAQ

¿n8n es realmente gratuito en self-hosted?

Sí, n8n Community Edition está bajo licencia Sustainable Use License (fork-friendly pero no para reventa as-is). En self-hosted, solo pagas el coste de tu servidor (5 a 20 EUR/mes en DigitalOcean, Hetzner, OVH para un setup estándar). La versión Cloud n8n.cloud es de pago (desde 20 EUR/mes) para quienes no quieren alojar. La diferencia crítica vs Zapier/Make: no hay pricing por ejecución. En Zapier, 5.000 zaps/mes te cuestan ~73 EUR/mes mínimo. En n8n self-hosted, 50.000 ejecuciones por día no cambian nada el coste de infra. Para una cuenta Google Ads que ejecuta 100+ workflows al día (hourly checks, daily reports), el ROI se inclina a favor de n8n desde el 3er mes.

¿Hace falta ser desarrollador para usar n8n con Google Ads?

Un nivel intermedio es suficiente. n8n es una herramienta low-code visual con un editor drag-drop (estilo Zapier) pero también permite JavaScript inline para transformaciones custom. Para los 6 flows que detallamos, necesitarás: entender una petición HTTP/REST (los nodes Google Ads de n8n llaman a la API directamente), saber leer un payload JSON, e idealmente haber generado una vez un OAuth refresh_token vía la consola Google. No necesitas escribir Python o TypeScript from scratch — la integración Google Ads está preconfigurada. Para workflows muy custom (ej.: ML inference antes de decisión), el node 'Code' permite embeber JavaScript o Python. Cuenta con 1 a 2 días de aprendizaje para ser autónomo en los flows básicos, 1 semana para dominar los flows avanzados.

¿Los workflows de n8n pueden funcionar 24/7 sin intervención?

Sí, ese es su diseño principal. Cada workflow tiene un trigger (cron schedule, webhook, polling, manual) y una vez activado, funciona en bucle según el trigger. n8n Worker en Docker mantiene la conexión abierta, retry automático en errores, log de cada ejecución en la DB. En las cuentas observadas en los benchmarks públicos de Google Ads, los workflows críticos (monitoring CPC, alertas anomalías) funcionan en continuo desde hace 12+ meses sin intervención manual más allá de los updates de versión. El único mantenimiento recurrente: refresh del refresh_token de Google Ads cada 90 días aproximadamente (si no, Google lo revoca), y update de n8n cada 1-2 meses para los security patches.

¿Cómo importar un workflow JSON en n8n?

Muy simple. En la interfaz de n8n, arriba a la derecha, clicar en los 3 puntos y luego 'Import from File' o 'Import from URL'. Pegar el contenido JSON o la URL del archivo. n8n carga el workflow con todos los nodes, las conexiones y las variables. Tras la importación, debes reconfigurar las credentials (Google Ads OAuth, Slack webhook, email SMTP) porque no están incluidas en la exportación JSON por razones de seguridad. Cuenta con 10 a 20 minutos para customizar un workflow importado para tu cuenta específica. El repo github.com/steerads/n8n-google-ads-flows contiene los 6 workflows JSON listos para importar, con un README que explica las variables a customizar para cada uno.

n8n vs Google Ads Scripts vs API directa: ¿cuándo elegir qué?

Pirámide de complejidad. Google Ads Scripts para lo rápido single-account (15 minutos de setup), sintaxis JS limitada pero hosted. n8n self-hosted para los workflows multi-sistema que orquestan Google Ads + CRM + Slack + email + sheets sin codear, con scheduler nativo y retry. API directa Python/Node para los workflows complejos de muy alto volumen (10.000+ ops/día) o cuando integras Google Ads en un producto interno. En las cuentas observadas en los benchmarks públicos, el patrón dominante para SMB y mid-market con equipo data ligero es: Scripts para lo táctico (alertas budget hourly), n8n para lo estratégico (sync CRM, reporting), API Python únicamente si el stack de data warehouse lo exige. Consulta nuestro comparativo Zapier vs Make para las opciones no-code complementarias.

Ready to optimize your campaigns?

Start a free audit in 2 minutes and discover the ROI potential of your accounts.

Start my free audit

Free audit — no credit card required

Keep reading