Comparación semanal de BrightData

Avanzado

Este es unAI, Marketingflujo de automatización del dominio deautomatización que contiene 35 nodos.Utiliza principalmente nodos como If, Set, Code, Gmail, Markdown, combinando tecnología de inteligencia artificial para lograr automatización inteligente. Monitoreo automatizado de cambios en sitios web con Bright Data, GPT-4.1 y Google Workspace

Requisitos previos
  • Cuenta de Google y credenciales de API de Gmail
  • Credenciales de API de Google Drive
  • Credenciales de API de Google Sheets
  • Clave de API de OpenAI
Vista previa del flujo de trabajo
Visualización de las conexiones entre nodos, con soporte para zoom y panorámica
Exportar flujo de trabajo
Copie la siguiente configuración JSON en n8n para importar y usar este flujo de trabajo
{
  "id": "pNaD8QIgVGDqbCoU",
  "meta": {
    "instanceId": "3af183a3db355380be4f6d2f3dfb18bdaa750e90f99a48f91bd71080ee6bcbe8",
    "templateCredsSetupCompleted": true
  },
  "name": "BrightData Weekly Comparison",
  "tags": [],
  "nodes": [
    {
      "id": "a2966ed3-e998-47ca-83b3-b7dc4832bc8f",
      "name": "Analizador de Salida Estructurada",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        700,
        140
      ],
      "parameters": {
        "jsonSchemaExample": "{\n  \"filename\": \"domain-path-DD-MM-YYYY.md\",\n  \"metadata\": {\n    \"pageTitle\": \"The primary title of the webpage\",\n    \"metaDescription\": \"The meta description content\"\n  },\n  \"headings\": {\n    \"h1\": [\"List of all H1 headings\"],\n    \"h2\": [\"List of all H2 headings\"],\n    \"h3\": [\"List of all H3 headings\"]\n  },\n  \"pricing\": [\n    {\n      \"planName\": \"Name of the pricing plan/tier\",\n      \"currency\": \"USD/EUR/GBP/etc.\",\n      \"interval\": \"monthly/yearly/one-time\",\n      \"price\": \"Numerical price value\",\n      \"features\": [\"List of features or benefits included in this plan\"]\n    }\n  ],\n  \"navigation\": {\n    \"mainMenu\": [\"Primary navigation items\"],\n    \"subMenu\": [\"Secondary navigation items if present\"]\n  },\n  \"callToAction\": [\"All CTA elements and their text\"],\n  \"contactInfo\": {\n    \"phone\": [\"Phone numbers found\"],\n    \"email\": [\"Email addresses found\"],\n    \"address\": [\"Physical addresses found\"],\n    \"formPresent\": true\n  },\n  \"banners\": [\"Content from promotional banners\"],\n  \"faq\": [\n    {\n      \"question\": \"FAQ question\",\n      \"answer\": \"FAQ answer\"\n    }\n  ]\n}"
      },
      "typeVersion": 1.2
    },
    {
      "id": "6d4b38bd-fb58-4675-9b83-ade043914d65",
      "name": "Establecer variables del flujo de trabajo",
      "type": "n8n-nodes-base.set",
      "position": [
        -260,
        -120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "96347cce-576a-413c-9c9b-b2257eced54d",
              "name": "DriveFolderID",
              "type": "string",
              "value": ""
            },
            {
              "id": "b2f5e75f-575d-40ed-89a8-1c2e537d3220",
              "name": "ComparisonSpreadsheetID",
              "type": "string",
              "value": ""
            },
            {
              "id": "f64718d6-a5f2-491e-abec-b26a6e6125e8",
              "name": "ComparisonSpreadsheetSheetName",
              "type": "string",
              "value": "Sheet1"
            },
            {
              "id": "1a71595c-58c3-4eda-9b7b-5c306123db86",
              "name": "Email",
              "type": "string",
              "value": ""
            },
            {
              "id": "ed5fe6bd-b43b-45b1-b1e8-b20beb329e4d",
              "name": "IsTest",
              "type": "boolean",
              "value": false
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "6ddda34f-556e-49a5-a103-7641a3f0598d",
      "name": "Combinar variables del flujo con datos de la hoja Google",
      "type": "n8n-nodes-base.set",
      "position": [
        180,
        -120
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e129ca16-8675-485e-9f21-e5d22b76c6e6",
              "name": "ComparisonSpreadsheetFileName",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.ComparisonSpreadsheetFileName }}"
            },
            {
              "id": "5fdee148-82eb-4542-9fe7-1ba37ec09571",
              "name": "ComparisonSpreadsheetSheetName",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.ComparisonSpreadsheetSheetName }}"
            },
            {
              "id": "7cce5924-a67a-45a2-8792-cd9ad28834b8",
              "name": "Email",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.Email }}"
            },
            {
              "id": "e445b570-384f-4558-99d3-12802b0fa900",
              "name": "DriveFolderID",
              "type": "string",
              "value": "={{ $('Set workflow variables').item.json.DriveFolderID }}"
            },
            {
              "id": "d487666e-4dd3-4d20-8769-d0daf3bab268",
              "name": "IsTest",
              "type": "boolean",
              "value": "={{ $('Set workflow variables').item.json.IsTest }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "45eefb28-dce0-4fc3-81a1-865762c73226",
      "name": "Leer desde hojas de cálculo de comparación",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -40,
        -120
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.ComparisonSpreadsheetSheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.ComparisonSpreadsheetID }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
      "name": "Bucle sobre cada URL de comparación",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        400,
        -115
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
      "name": "Agente de scraping web y extracción de datos",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        652,
        -365
      ],
      "parameters": {
        "text": "=Please scrape the following url {{ $json.URL }}\n",
        "options": {
          "systemMessage": "=## Role\nYou are an expert Web Data Extraction Specialist with a specialization in content analysis, information architecture, and structured data organization.\n\n## Task\nYour primary task is to extract, organize, and present key website components from any URL provided by the user.\nTo achieve this, you will need to perform the following:\n- Scrape the target webpage using the scrape_as_markdown tool to obtain its content\n- Generate a clean filename based on the URL and current date for storing the content as JSON\n- Systematically extract and categorize the following elements from the markdown content\n- Format the extracted data into a structured JSON object containing the processed elements\n\n## Tools\nYou can use the following tools:\n1. **scrape_as_markdown**: Use this tool to extract the full content of a webpage in Markdown format. This tool can bypass bot detection and CAPTCHA systems to ensure reliable extraction.\n\n## Input\nYou will receive input as a URL to the webpage that requires data extraction.\n\n## Output\nYour output must be a single, valid JSON object containing all extracted elements and a clean filename. Do not include any explanatory text before or after the JSON.\n\n{\n  \"filename\": \"domain-path-DD-MM-YYYY.json\",\n  \"metadata\": {\n    \"pageTitle\": \"The primary title of the webpage\",\n    \"metaDescription\": \"The meta description content\"\n  },\n  \"headings\": {\n    \"h1\": [\"List of all H1 headings\"],\n    \"h2\": [\"List of all H2 headings\"],\n    \"h3\": [\"List of all H3 headings\"]\n  },\n  \"pricing\": [\n    {\n      \"planName\": \"Name of the pricing plan/tier\",\n      \"currency\": \"USD/EUR/GBP/etc.\",\n      \"interval\": \"monthly/yearly/one-time\",\n      \"price\": \"Numerical price value\",\n      \"features\": [\"List of features or benefits included in this plan\"]\n    }\n  ],\n  \"navigation\": {\n    \"mainMenu\": [\"Primary navigation items\"],\n    \"subMenu\": [\"Secondary navigation items if present\"]\n  },\n  \"callToAction\": [\"All CTA elements and their text\"],\n  \"contactInfo\": {\n    \"phone\": [\"Phone numbers found\"],\n    \"email\": [\"Email addresses found\"],\n    \"address\": [\"Physical addresses found\"],\n    \"formPresent\": true/false\n  },\n  \"banners\": [\"Content from promotional banners\"],\n  \"faq\": [\n    {\n      \"question\": \"FAQ question\",\n      \"answer\": \"FAQ answer\"\n    }\n  ]\n}\n\nFor any elements not found on the webpage, include an empty array [] or appropriate null value. Ensure the JSON is properly formatted and valid. If the extraction process encounters any errors, include an additional \"errors\" key with relevant details.\n\nWhen extracting pricing information, analyze the webpage carefully to identify all pricing plans. For each plan, determine:\n- The name of the plan (e.g., \"Basic\", \"Pro\", \"Enterprise\")\n- The currency symbol or code used\n- Whether the pricing is monthly, yearly, or one-time\n- The numerical price value\n- All features or details associated with that pricing tier\n\nThe filename should be generated using the following format:\n- Extract the domain name from the URL (without www.)\n- Extract the path (without any query parameters or fragments)\n- Replace slashes with hyphens\n- Add the current date in DD-MM-YYYY format\n- Use .json as the file extension\n- For example, if the URL is https://asana.com/pricing and today is May 20, 2025, the filename would be \"asana-pricing-20-05-2025.json\"\n- Today's date is {{ $now }}\n\nEven if some pricing information is ambiguous or incomplete, make reasonable inferences and include all relevant details in the structured format."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "c1f69dc5-6612-4575-aaf4-1d6a7a70c423",
      "name": "Subir archivo JSON de la semana actual",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1280,
        -365
      ],
      "parameters": {
        "name": "={{ $('Web scraping and data extraction agent').item.json.output.filename }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive",
          "cachedResultUrl": "https://drive.google.com/drive/my-drive",
          "cachedResultName": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Loop over each comparison URL').item.json.DriveFolderID }}"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ENsCK6J7JBSny3Pv",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95",
      "name": "Actualizar hoja de comparación con datos del archivo de la semana actual",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1500,
        -365
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Loop over each comparison URL').item.json.URL }}",
            "Previous Week ID": "={{ $('Loop over each comparison URL').item.json[\"Current Week File ID\"] }}",
            "Current Week File ID": "={{ $json.id }}",
            "Current Week File Link": "={{ $json.webViewLink }}",
            "Previous Week File Link": "={{ $('Loop over each comparison URL').item.json[\"Current Week File Link\"] }}"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Previous Week ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week File Link",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Previous Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Current Week File ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File Link",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Current Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Comparison File",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Comparison File",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit?usp=drivesdk",
          "cachedResultName": "BrightData Scraping Comparison"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "32934604-9e72-4f6a-aa55-fc0abff1d85c",
      "name": "Verificar presencia del archivo de la semana anterior",
      "type": "n8n-nodes-base.if",
      "position": [
        1720,
        -365
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "d46019c6-ec3b-4e8b-80b2-44ffb2a82e51",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json[\"Previous Week ID\"] }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "301dfc46-f1d4-4b1a-892b-25ecb4495b77",
      "name": "Descargar archivo de la semana anterior",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1940,
        -365
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json[\"Previous Week ID\"] }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "id": "ENsCK6J7JBSny3Pv",
          "name": "Google Drive account"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "036d00c9-7414-4883-ac56-ef9368195b85",
      "name": "Convertir archivo de la semana anterior a JSON",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        2160,
        -365
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson"
      },
      "typeVersion": 1
    },
    {
      "id": "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1",
      "name": "Establecer semana anterior y semana actual",
      "type": "n8n-nodes-base.set",
      "position": [
        2380,
        -365
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "af75985e-4f86-4493-9fbd-0d0c7b383001",
              "name": "previous",
              "type": "object",
              "value": "={{ $json.data[0].output }}"
            },
            {
              "id": "718aeb81-59e9-49f9-aa5b-dc3c194d2efa",
              "name": "current",
              "type": "object",
              "value": "={{ $('Web scraping and data extraction agent').item.json.output }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0",
      "name": "Verificar si es modo de prueba",
      "type": "n8n-nodes-base.if",
      "position": [
        2600,
        -365
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "650a5f5e-3041-4d2f-a891-1d369b09c17a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $('Loop over each comparison URL').item.json.IsTest }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "af562b9f-3cfc-4715-ae47-779a0554e7d2",
      "name": "Simular cambios de la semana anterior",
      "type": "n8n-nodes-base.code",
      "position": [
        2820,
        -440
      ],
      "parameters": {
        "jsCode": "// Code node in N8n\nconst inputData = $input.first().json;\n\n// Clone the previous data before modifying it\nconst previous = {...inputData.previous};\n\n// Change 1: Increase all numeric prices by $5 in the pricing array\nif (previous?.pricing && Array.isArray(previous.pricing)) {\n  previous.pricing.forEach(plan => {\n    // Check if price is a numeric string\n    if (plan.price && !isNaN(parseFloat(plan.price))) {\n      // Add $5 to the price\n      plan.price = (parseFloat(plan.price) + 5).toString();\n    }\n  });\n}\n\n// Change 2: Modify a feature in the first paid plan (if exists)\nif (previous?.pricing && previous.pricing.length > 1) {\n  const firstPaidPlan = previous.pricing.find(plan => \n    plan.price && plan.price !== \"0\" && !isNaN(parseFloat(plan.price)));\n  \n  if (firstPaidPlan && Array.isArray(firstPaidPlan.features) && firstPaidPlan.features.length > 1) {\n    // Add \"Premium\" prefix to the second feature (if it exists)\n    if (firstPaidPlan.features[1]) {\n      firstPaidPlan.features[1] = \"Premium \" + firstPaidPlan.features[1];\n    }\n  }\n}\n\n// Change 3: Update the first FAQ answer (if exists)\nif (previous?.faq && Array.isArray(previous.faq) && previous.faq.length > 0) {\n  if (previous.faq[0] && previous.faq[0].answer) {\n    // Add a sentence to the end of the answer\n    previous.faq[0].answer += \" For more information, contact our sales team.\";\n  }\n}\n\n// Return the data with current and modified previous\nreturn [{\n  json: {\n    current: inputData.current,\n    previous: previous\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
      "name": "Detectar cambios entre semanas",
      "type": "n8n-nodes-base.code",
      "position": [
        3040,
        -365
      ],
      "parameters": {
        "jsCode": "// N8n Code Node to compare previous and current data\n// Input: $input.first().json contains previous and current data objects\n\nfunction detectChanges() {\n  const previous = $input.first().json.previous;\n  const current = $input.first().json.current;\n  \n  // Initialize changes object with better structure for Markdown generation\n  const changes = {\n    detected: false,\n    sections: {}, // Organized by section\n    summary: {\n      totalChanges: 0,\n      timestamp: new Date().toISOString()\n    }\n  };\n  \n  // Helper function to add a change to the changes object\n  function addChange(section, path, changeType, changeData) {\n    // Initialize section if it doesn't exist\n    if (!changes.sections[section]) {\n      changes.sections[section] = {\n        name: formatSectionName(section),\n        changes: []\n      };\n    }\n    \n    // Format display path\n    const displayPath = formatPath(path);\n    \n    // Add change to the section\n    changes.sections[section].changes.push({\n      displayPath,\n      type: changeType,\n      ...changeData\n    });\n    \n    // Update global detected flag and counter\n    changes.detected = true;\n    changes.summary.totalChanges++;\n  }\n  \n  // Helper function to format section name for display\n  function formatSectionName(name) {\n    // Convert camelCase to Title Case with spaces\n    return name.replace(/([A-Z])/g, ' $1')\n      .replace(/^./, str => str.toUpperCase())\n      .trim();\n  }\n  \n  // Helper function to format path for display\n  function formatPath(path) {\n    // Format the path elements to be more readable\n    return path.replace(/\\[([^\\]]+)\\]/g, ' ($1)');\n  }\n  \n  // Helper function to compare primitive values\n  function compareValues(prevVal, currVal, path) {\n    if (prevVal !== currVal) {\n      const section = path.split('.')[0];\n      addChange(section, path, 'changed', {\n        old: prevVal,\n        new: currVal\n      });\n      return true;\n    }\n    return false;\n  }\n  \n  // Helper function to compare arrays\n  function compareArrays(prevArr, currArr, path, matchKey = null) {\n    let changed = false;\n    const section = path.split('.')[0];\n    const additions = [];\n    const deletions = [];\n    \n    // Check for deletions\n    for (let i = 0; i < prevArr.length; i++) {\n      const prevItem = prevArr[i];\n      \n      if (matchKey && typeof prevItem === 'object' && prevItem !== null) {\n        // For arrays of objects with a specified match key (like planName or question)\n        const matchFound = currArr.some(currItem => currItem[matchKey] === prevItem[matchKey]);\n        if (!matchFound) {\n          deletions.push(prevItem);\n          changed = true;\n        }\n      } else {\n        // For arrays of primitives\n        if (!currArr.includes(prevItem)) {\n          deletions.push(prevItem);\n          changed = true;\n        }\n      }\n    }\n    \n    // Check for additions\n    for (let i = 0; i < currArr.length; i++) {\n      const currItem = currArr[i];\n      \n      if (matchKey && typeof currItem === 'object' && currItem !== null) {\n        // For arrays of objects with a specified match key\n        const matchFound = prevArr.some(prevItem => prevItem[matchKey] === currItem[matchKey]);\n        if (!matchFound) {\n          additions.push(currItem);\n          changed = true;\n        }\n      } else {\n        // For arrays of primitives\n        if (!prevArr.includes(currItem)) {\n          additions.push(currItem);\n          changed = true;\n        }\n      }\n    }\n    \n    // Check for changes in matching objects\n    if (matchKey) {\n      for (let i = 0; i < currArr.length; i++) {\n        const currItem = currArr[i];\n        if (typeof currItem === 'object' && currItem !== null) {\n          const matchingPrevItem = prevArr.find(prevItem => prevItem[matchKey] === currItem[matchKey]);\n          if (matchingPrevItem) {\n            // Compare the matching objects recursively\n            const itemPath = `${path}[${matchKey}=${currItem[matchKey]}]`;\n            compareObjects(matchingPrevItem, currItem, itemPath);\n          }\n        }\n      }\n    }\n    \n    if (changed) {\n      addChange(section, path, 'array_changed', {\n        additions: additions.length > 0 ? additions : null,\n        deletions: deletions.length > 0 ? deletions : null\n      });\n    }\n    \n    return changed;\n  }\n  \n  // Helper function to compare objects\n  function compareObjects(prevObj, currObj, path = '') {\n    if (!prevObj || !currObj) return false;\n    \n    const allKeys = new Set([...Object.keys(prevObj), ...Object.keys(currObj)]);\n    let changed = false;\n    \n    for (const key of allKeys) {\n      // Skip rawMarkdown as requested\n      if (key === 'rawMarkdown') continue;\n      \n      const keyPath = path ? `${path}.${key}` : key;\n      const section = keyPath.split('.')[0];\n      const prevVal = prevObj[key];\n      const currVal = currObj[key];\n      \n      // Handle missing keys\n      if (!(key in prevObj)) {\n        addChange(section, keyPath, 'added', {\n          value: currVal\n        });\n        changed = true;\n        continue;\n      }\n      \n      if (!(key in currObj)) {\n        addChange(section, keyPath, 'removed', {\n          value: prevVal\n        });\n        changed = true;\n        continue;\n      }\n      \n      // Compare based on type\n      if (Array.isArray(prevVal) && Array.isArray(currVal)) {\n        // Special handling for specific array types\n        if (key === 'pricing') {\n          compareArrays(prevVal, currVal, keyPath, 'planName');\n        } else if (key === 'features') {\n          compareArrays(prevVal, currVal, keyPath);\n        } else if (key === 'faq') {\n          compareArrays(prevVal, currVal, keyPath, 'question');\n        } else {\n          compareArrays(prevVal, currVal, keyPath);\n        }\n      } else if (\n        typeof prevVal === 'object' && prevVal !== null &&\n        typeof currVal === 'object' && currVal !== null\n      ) {\n        compareObjects(prevVal, currVal, keyPath);\n      } else {\n        compareValues(prevVal, currVal, keyPath);\n      }\n    }\n    \n    return changed;\n  }\n  \n  // Start comparison - removed the .output reference\n  compareObjects(previous, current);\n  \n  return [{ json: {previous, current, changes} }];\n}\n\n// Execute the function and return the results\nreturn detectChanges();"
      },
      "typeVersion": 2
    },
    {
      "id": "e5a8b7c1-53ec-4a26-8791-30db494cde92",
      "name": "Generar Markdown a partir de cambios detectados",
      "type": "n8n-nodes-base.code",
      "position": [
        3260,
        -365
      ],
      "parameters": {
        "jsCode": "// N8n Code Node to generate Markdown from structured changes\n// Input: $input.changes contains the comparison results from the improved comparison node\nfunction generateChangelogMarkdown() {\n  // Changed to directly access the changes property from the input\n  const changes = $input.first().json.changes;\n  \n  if (!changes || !changes.detected) {\n    return [{ json: { markdown: \"# Changelog\\n\\nNo changes detected.\" }}];\n  }\n  \n  // Start building the markdown\n  // Getting the filename from the input for the title\n  let fileNameWithoutExt = '';\n  try {\n    // Try to get the filename from the Loop Over Items node if available\n    fileNameWithoutExt = $('Loop over each comparison URL').first().json[\"\"][0];\n  } catch (e) {\n    // Fallback to a generic title if the loop node isn't available\n    fileNameWithoutExt = \"Website\";\n  }\n  \n  let markdown = `# ${fileNameWithoutExt} Changes\\n\\n`;\n  \n  // Process each section in the changes object\n  Object.values(changes.sections).forEach(section => {\n    markdown += `## ${section.name}\\n\\n`;\n    \n    // Process each change in this section\n    section.changes.forEach(change => {\n      switch (change.type) {\n        case 'changed':\n          markdown += `- **${change.displayPath}** changed from \\`${formatValue(change.old)}\\` to \\`${formatValue(change.new)}\\`\\n`;\n          break;\n          \n        case 'added':\n          markdown += `- **${change.displayPath}** was added with value \\`${formatValue(change.value)}\\`\\n`;\n          break;\n          \n        case 'removed':\n          markdown += `- **${change.displayPath}** was removed (previously \\`${formatValue(change.value)}\\`)\\n`;\n          break;\n          \n        case 'array_changed':\n          markdown += `- **${change.displayPath}** has changes:\\n`;\n          \n          // Handle additions\n          if (change.additions && change.additions.length > 0) {\n            markdown += `  - **Added**:\\n`;\n            change.additions.forEach(item => {\n              markdown += `    - \\`${formatValue(item)}\\`\\n`;\n            });\n          }\n          \n          // Handle deletions\n          if (change.deletions && change.deletions.length > 0) {\n            markdown += `  - **Removed**:\\n`;\n            change.deletions.forEach(item => {\n              markdown += `    - \\`${formatValue(item)}\\`\\n`;\n            });\n          }\n          break;\n      }\n    });\n    \n    markdown += '\\n';\n  });\n  \n  // Add summary section\n  markdown += `## Summary\\n\\n`;\n  markdown += `Total changes detected: **${changes.summary.totalChanges}**\\n\\n`;\n  markdown += `Generated on: **${new Date(changes.summary.timestamp).toLocaleDateString('en-US', {\n    year: 'numeric',\n    month: 'long',\n    day: 'numeric'\n  })}**\\n`;\n  \n  // Return in the format expected by n8n\n  return [{ json: { markdown } }];\n}\n\n// Helper function to format values for markdown display\nfunction formatValue(value) {\n  if (value === null || value === undefined) {\n    return 'null';\n  } else if (typeof value === 'object') {\n    if (Array.isArray(value)) {\n      // For arrays, simplify to show length\n      if (value.length === 0) return '[]';\n      if (value.length > 3) {\n        return `[Array with ${value.length} items]`;\n      }\n      // For small arrays, show the items\n      return JSON.stringify(value).substring(0, 60) + (JSON.stringify(value).length > 60 ? '...' : '');\n    }\n    \n    // For objects with a name or key identifier, try to use that\n    if (value.name) return value.name;\n    if (value.title) return value.title;\n    if (value.id) return value.id;\n    if (value.planName) return value.planName;\n    if (value.question) return value.question;\n    \n    // For other objects, shorten to reasonable length\n    const objStr = JSON.stringify(value);\n    return objStr.substring(0, 60) + (objStr.length > 60 ? '...' : '');\n  } else if (typeof value === 'string') {\n    // For strings, add quoting\n    return value;\n  } else {\n    // For other primitives, convert to string\n    return String(value);\n  }\n}\n\n// Execute the function and return the markdown result\nreturn generateChangelogMarkdown();"
      },
      "typeVersion": 2
    },
    {
      "id": "16c9f196-6acf-4d3a-946b-727c121b503a",
      "name": "Convertir Markdown a HTML",
      "type": "n8n-nodes-base.markdown",
      "position": [
        3480,
        -365
      ],
      "parameters": {
        "mode": "markdownToHtml",
        "options": {},
        "markdown": "={{ $json.markdown }}"
      },
      "typeVersion": 1
    },
    {
      "id": "3df4c31f-db47-40a5-9140-d2de7b1fbf2e",
      "name": "Crear documento de comparación",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        3700,
        -365
      ],
      "parameters": {
        "title": "={{ $('Web scraping and data extraction agent').first().json.output.filename.replace(/\\.[^/.]+$/, '') + '-comparison.md' }}",
        "folderId": "default"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "id": "T3HEUOkeb37yLim7",
          "name": "Google Docs account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "da24c1a3-fa3b-4b06-b5b9-78dd6d872756",
      "name": "Actualizar documento de comparación con resultados",
      "type": "n8n-nodes-base.googleDocs",
      "position": [
        3920,
        -365
      ],
      "parameters": {
        "actionsUi": {
          "actionFields": [
            {
              "text": "={{ $('Convert Markdown to HTML').item.json.data }}",
              "action": "insert"
            }
          ]
        },
        "operation": "update",
        "documentURL": "={{ $json.id }}"
      },
      "credentials": {
        "googleDocsOAuth2Api": {
          "id": "T3HEUOkeb37yLim7",
          "name": "Google Docs account"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "b532d34b-0ac0-4a00-9949-a9a959e27b31",
      "name": "Actualizar hoja de cálculo con archivo de comparación",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        4140,
        -365
      ],
      "parameters": {
        "columns": {
          "value": {
            "URL": "={{ $('Loop over each comparison URL').item.json.URL }}",
            "Comparison File": "=https://docs.google.com/document/d/{{ $json.documentId }}"
          },
          "schema": [
            {
              "id": "URL",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week ID",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Previous Week ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Previous Week File Link",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Previous Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File ID",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Current Week File ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Current Week File Link",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Current Week File Link",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Comparison File",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Comparison File",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "string",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "URL"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk/edit?usp=drivesdk",
          "cachedResultName": "BrightData Scraping Comparison"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "vnXMSwscCP06bp9u",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "7ef3ba20-c79e-4d49-8a68-c11d20c77def",
      "name": "Enviar correo electrónico con resultados de comparación",
      "type": "n8n-nodes-base.gmail",
      "position": [
        4340,
        -260
      ],
      "webhookId": "8d51cb0f-f585-4222-93dd-2fffcead588e",
      "parameters": {
        "sendTo": "dave@emberautomation.com",
        "message": "={{ $('Convert Markdown to HTML').item.json.data }}",
        "options": {},
        "subject": "={{ $now.format('yyyy-MM-dd') }}: {{ $('Loop over each comparison URL').item.json.URL }} weekly comparison"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "nkZOm8cNEGHWhTE4",
          "name": "Gmail account"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "a0926fe8-80c2-456b-b9c2-4dc1675c408c",
      "name": "Nota Adhesiva",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        -1340
      ],
      "parameters": {
        "width": 760,
        "height": 1060,
        "content": "# BrightData Weekly Comparison\n## Overview\nThis workflow tracks changes on web pages, compares data, generates change reports, saves to Drive, and sends email notifications. **The workflow runs automatically on a weekly basis.**\n\n## Prerequisites\n- **Bright Data MCP Server**: Set up a Bright Data MCP server for web scraping\n- **n8n MCP Client Node**: Install the community node from `n8n-nodes-mcp` (https://www.npmjs.com/package/n8n-nodes-mcp)\n\n## Setup Steps\n1. **Duplicate Spreadsheet**\n   - Make a copy of the comparison spreadsheet: [Sheet to Copy](https://docs.google.com/spreadsheets/d/1oPyAaTS8GMqlaBcyCO7G7MRtzMUUaOnA45JfWCzcCa8/edit?usp=sharing)\n   - Update the URLs of web pages to track\n\n2. **Configure Variables**\n   - Open the \"Set workflow variables\" node\n   - Update these values:\n     - `DriveFolderID`: Your Google Drive folder ID\n     - `ComparisonSpreadsheetFileID`: `1e4oheZjmxb3P7OXGY0uLWZKz2ENcp7XlEpIloOtRHEk` (or your copied spreadsheet ID)\n     - `ComparisonSpreadsheetSheetName`: Sheet name (usually \"Sheet1\")\n     - `Email`: Where to send reports\n     - `IsTest`: Set to `true` only for testing (set to `false` for regular operation)\n\n3. **Configure Bright Data MCP**\n   - Set up your Bright Data MCP credentials in the MCP client node\n   - Configure the MCP server using the documentation: https://github.com/luminati-io/brightdata-mcp\n\n4. **Set Up Credentials**\n   - Configure credentials for:\n     - Google Sheets\n     - Google Drive\n     - Google Docs\n     - Gmail\n     - OpenAI (or alternative AI provider)\n     - Bright Data MCP\n\n5. **Run Workflow**\n   - Execute the workflow manually to test\n   - Check your Drive folder and email for results\n   - **Once setup is complete, the workflow will run automatically every week**"
      },
      "typeVersion": 1
    },
    {
      "id": "33c8b369-b6f7-4bb9-87e2-d202d998255d",
      "name": "GPT-4.1",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        620,
        -145
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1",
          "cachedResultName": "gpt-4.1"
        },
        "options": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "NuECwZyKpEfWhSN1",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "700e8bb2-607d-4889-b248-88bf6464c587",
      "name": "Activador Programado",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -480,
        -120
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                3
              ],
              "triggerAtHour": 12
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "c2919b53-c13f-4033-86f2-3b4e2e28dfa8",
      "name": "scrape_as_markdown",
      "type": "n8n-nodes-mcp.mcpClientTool",
      "position": [
        740,
        -145
      ],
      "parameters": {
        "toolName": "scrape_as_markdown",
        "operation": "executeTool",
        "toolParameters": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"
      },
      "credentials": {
        "mcpClientApi": {
          "id": "mO1My0js13704jqM",
          "name": "MCP Client (STDIO) account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
      "name": "Analizador de Salida con Auto-corrección",
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "position": [
        640,
        20
      ],
      "parameters": {
        "options": {
          "prompt": "Instructions:\n--------------\n{instructions}\n--------------\nCompletion:\n--------------\n{completion}\n--------------\n\nAbove, the Completion did not satisfy the constraints given in the Instructions.\nError:\n--------------\n{error}\n--------------\n\nPlease try again. Please only respond with an answer that satisfies the constraints laid out in the Instructions:"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f3766efe-53a7-4311-9b53-af9f8d11b292",
      "name": "Nota Adhesiva1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -540,
        -260
      ],
      "parameters": {
        "color": 2,
        "width": 220,
        "height": 340,
        "content": "## Scheduled Weekly"
      },
      "typeVersion": 1
    },
    {
      "id": "93f1107c-8e81-439b-a912-5900e36afd8b",
      "name": "Nota Adhesiva2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -280,
        -260
      ],
      "parameters": {
        "color": 3,
        "width": 620,
        "height": 340,
        "content": "## Initialization\nInitializes the workflow variables, reads the main spreadsheet, then merges the spreadsheet results with the main workflow variables. "
      },
      "typeVersion": 1
    },
    {
      "id": "f4882880-6ee4-4a44-9967-1be01de7151c",
      "name": "Nota Adhesiva3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        580,
        -520
      ],
      "parameters": {
        "color": 4,
        "width": 400,
        "height": 780,
        "content": "## AI Scraping\nFor the given URL, the agent will use the Scrape as Markdown tool to scrape the page getting the content as Markdown. It will then generate a JSON structure, extracting out relevant information from the page. "
      },
      "typeVersion": 1
    },
    {
      "id": "8f6da1fd-c91a-4c99-94f8-b2464a0786be",
      "name": "Nota Adhesiva4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1020,
        -520
      ],
      "parameters": {
        "color": 5,
        "width": 860,
        "height": 400,
        "content": "## Process current week results\nThe agent's response is turned into a binary file and then saved in Google Drive for the next week. Then the main spreadsheet is updated with that file. Finally checking if we have a previous week to compare this week to. If not, we finish and move on to the next item. If we do, then we move on and process the previous week's results vs the current week. "
      },
      "typeVersion": 1
    },
    {
      "id": "25f758b4-2e11-4cde-bcc3-1a8e53106d29",
      "name": "Nota Adhesiva5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1900,
        -520
      ],
      "parameters": {
        "color": 6,
        "width": 640,
        "height": 400,
        "content": "## Process previous week results\nRead the previous week's ID and download the file from Google Drive. Then, set variables ready for processing. "
      },
      "typeVersion": 1
    },
    {
      "id": "f8d7c276-9540-431d-860d-10e15b769fe4",
      "name": "Nota Adhesiva6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2560,
        -520
      ],
      "parameters": {
        "color": 7,
        "width": 440,
        "height": 400,
        "content": "## Mocking\nIf we are in test mode, then this will mock example changes. Otherwise, it will carry on as normal. "
      },
      "typeVersion": 1
    },
    {
      "id": "c2dfbe5e-e79e-4cc8-91f2-a61bfef2721e",
      "name": "Nota Adhesiva7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3020,
        -520
      ],
      "parameters": {
        "color": 2,
        "width": 1260,
        "height": 400,
        "content": "## Current week vs previous week comparison\nUsing code notes, we detect the changes from the previous week vs the current week and then convert that to a Markdown document and then use the Markdown to HTML node.  Finally, creating a document in Google Docs, and then updating the main spreadsheet with that comparison document. "
      },
      "typeVersion": 1
    },
    {
      "id": "a261bcd8-91a1-40f4-928f-19013b68b998",
      "name": "Convertir respuesta JSON de la semana actual a archivo",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1060,
        -365
      ],
      "parameters": {
        "options": {},
        "operation": "toJson"
      },
      "typeVersion": 1.1
    },
    {
      "id": "dc49334a-6d00-4476-b84c-7bddfa3c0911",
      "name": "Nota Adhesiva8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4300,
        -520
      ],
      "parameters": {
        "width": 380,
        "height": 400,
        "content": "## Send the comparison email"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "3556e422-eddc-40df-8f4f-860d621258d4",
  "connections": {
    "33c8b369-b6f7-4bb9-87e2-d202d998255d": {
      "ai_languageModel": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_languageModel",
            "index": 0
          },
          {
            "node": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "700e8bb2-607d-4889-b248-88bf6464c587": {
      "main": [
        [
          {
            "node": "6d4b38bd-fb58-4675-9b83-ade043914d65",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0": {
      "main": [
        [
          {
            "node": "af562b9f-3cfc-4715-ae47-779a0554e7d2",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c2919b53-c13f-4033-86f2-3b4e2e28dfa8": {
      "ai_tool": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "6d4b38bd-fb58-4675-9b83-ade043914d65": {
      "main": [
        [
          {
            "node": "45eefb28-dce0-4fc3-81a1-865762c73226",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "16c9f196-6acf-4d3a-946b-727c121b503a": {
      "main": [
        [
          {
            "node": "3df4c31f-db47-40a5-9140-d2de7b1fbf2e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a2966ed3-e998-47ca-83b3-b7dc4832bc8f": {
      "ai_outputParser": [
        [
          {
            "node": "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "cbbfbf09-9d2b-4c3b-bcbc-fc43f198f0c0": {
      "ai_outputParser": [
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "3df4c31f-db47-40a5-9140-d2de7b1fbf2e": {
      "main": [
        [
          {
            "node": "da24c1a3-fa3b-4b06-b5b9-78dd6d872756",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "af562b9f-3cfc-4715-ae47-779a0554e7d2": {
      "main": [
        [
          {
            "node": "dd764b6d-d412-44e6-8816-e7b66bbb44c6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "dd764b6d-d412-44e6-8816-e7b66bbb44c6": {
      "main": [
        [
          {
            "node": "e5a8b7c1-53ec-4a26-8791-30db494cde92",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "301dfc46-f1d4-4b1a-892b-25ecb4495b77": {
      "main": [
        [
          {
            "node": "036d00c9-7414-4883-ac56-ef9368195b85",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c04cec36-1664-48d7-a9ae-a5665bc2c188": {
      "main": [
        [],
        [
          {
            "node": "c50e3ec4-c3bf-4417-94ad-5b57ad6424da",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c1f69dc5-6612-4575-aaf4-1d6a7a70c423": {
      "main": [
        [
          {
            "node": "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7ef3ba20-c79e-4d49-8a68-c11d20c77def": {
      "main": [
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "45eefb28-dce0-4fc3-81a1-865762c73226": {
      "main": [
        [
          {
            "node": "6ddda34f-556e-49a5-a103-7641a3f0598d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1": {
      "main": [
        [
          {
            "node": "40b828f7-08f2-41ea-a6f7-595c5e4ae3e0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "036d00c9-7414-4883-ac56-ef9368195b85": {
      "main": [
        [
          {
            "node": "67b8ee0a-2ab0-43cd-b24f-0c8ba6b04cd1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "32934604-9e72-4f6a-aa55-fc0abff1d85c": {
      "main": [
        [
          {
            "node": "301dfc46-f1d4-4b1a-892b-25ecb4495b77",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c50e3ec4-c3bf-4417-94ad-5b57ad6424da": {
      "main": [
        [
          {
            "node": "a261bcd8-91a1-40f4-928f-19013b68b998",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e5a8b7c1-53ec-4a26-8791-30db494cde92": {
      "main": [
        [
          {
            "node": "16c9f196-6acf-4d3a-946b-727c121b503a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "da24c1a3-fa3b-4b06-b5b9-78dd6d872756": {
      "main": [
        [
          {
            "node": "b532d34b-0ac0-4a00-9949-a9a959e27b31",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a261bcd8-91a1-40f4-928f-19013b68b998": {
      "main": [
        [
          {
            "node": "c1f69dc5-6612-4575-aaf4-1d6a7a70c423",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6ddda34f-556e-49a5-a103-7641a3f0598d": {
      "main": [
        [
          {
            "node": "c04cec36-1664-48d7-a9ae-a5665bc2c188",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "b532d34b-0ac0-4a00-9949-a9a959e27b31": {
      "main": [
        [
          {
            "node": "7ef3ba20-c79e-4d49-8a68-c11d20c77def",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "e4a1fd2c-e1a5-4065-a9c8-76d1c854af95": {
      "main": [
        [
          {
            "node": "32934604-9e72-4f6a-aa55-fc0abff1d85c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Preguntas frecuentes

¿Cómo usar este flujo de trabajo?

Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.

¿En qué escenarios es adecuado este flujo de trabajo?

Avanzado - Inteligencia Artificial, Marketing

¿Es de pago?

Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.

Información del flujo de trabajo
Nivel de dificultad
Avanzado
Número de nodos35
Categoría2
Tipos de nodos18
Descripción de la dificultad

Adecuado para usuarios avanzados, flujos de trabajo complejos con 16+ nodos

Autor
Daniel Shashko

Daniel Shashko

@tomax

AI automation specialist and a marketing enthusiast. More than 6 years of experience in SEO/GEO. Senior SEO at Bright Data.

Enlaces externos
Ver en n8n.io

Compartir este flujo de trabajo

Categorías

Categorías: 34