8
n8n 한국어amn8n.com

경쟁사 콘텐츠 격차 분석기: 자동화된 웹사이트 주제 매핑

고급

이것은Miscellaneous, AI Summarization, Multimodal AI분야의자동화 워크플로우로, 30개의 노드를 포함합니다.주로 If, Set, Code, Gmail, Merge 등의 노드를 사용하며. Gemini AI, Apify, Google Sheets를 사용한 경쟁사 콘텐츠 격차 분석

사전 요구사항
  • Google 계정 및 Gmail API 인증 정보
  • HTTP Webhook 엔드포인트(n8n이 자동으로 생성)
  • 대상 API의 인증 정보가 필요할 수 있음
  • Google Sheets API 인증 정보
  • Google Gemini API Key
워크플로우 미리보기
노드 연결 관계를 시각적으로 표시하며, 확대/축소 및 이동을 지원합니다
워크플로우 내보내기
다음 JSON 구성을 복사하여 n8n에 가져오면 이 워크플로우를 사용할 수 있습니다
{
  "id": "MVDc7al8dnpBvlD2",
  "meta": {
    "instanceId": "d1dc073e8e3059a23e2730f69cb1b90065a2ac39039fea0727fdf9bee77a9131",
    "templateCredsSetupCompleted": true
  },
  "name": "Competitor Content Gap Analyzer: Automated Website Topic Mapping",
  "tags": [],
  "nodes": [
    {
      "id": "8d912fd2-61b3-41df-9631-c7eaf6050bc9",
      "name": "AI 에이전트",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1696,
        -32
      ],
      "parameters": {
        "text": "=You are a competitive content analyst.\nAnalyze the competitor website page provided in `markdown`.\n\nReturn ONLY valid JSON matching this schema:\n\n{\n  \"page_url\": \"string\",\n  \"title\": \"string\",\n  \"content_type\": \"string\",\n  \"main_topics\": [\n    {\n      \"topic\": \"string\",\n      \"level\": \"number (must start at 1 for top-level)\",\n      \"subtopics\": [\n        {\n          \"topic\": \"string\",\n          \"level\": \"number (increment by 1 for each deeper heading)\",\n          \"subtopics\": []\n        }\n      ]\n    }\n  ],\n  \"key_entities\": [\"string\"],\n  \"depth_score_1_to_5\": \"number\"\n}\n\nRules:\n- Strict JSON output. No extra text, no explanations.\n- content_type: choose from [\"landing\",\"blog\",\"service\",\"about\"].\n- \"main_topics\" must always start at level 1.\n- Subtopics increment level by +1 relative to their parent.\n- If no subtopics, return [].\n- Always close JSON properly.\n\nContent to analyze:\n{{ $json[\"markdown\"] }}\n",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "d09b94e5-09d8-4477-9034-843079795ea3",
      "name": "스티키 노트",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        -928
      ],
      "parameters": {
        "width": 304,
        "height": 304,
        "content": "## Competitor Content Gap Analyzer: Automated Website Topic Mapping\nStay ahead of competitors by uncovering their content strategies automatically. This workflow crawls competitor websites, extracts structured topic hierarchies, entities, and depth scores, and delivers actionable insights directly into Google Sheets—no more manual browsing, just clean, analyzable data you can act on.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "a9a4fa59-bc0a-4175-afd8-46855bb271d3",
      "name": "Apify 입력 준비",
      "type": "n8n-nodes-base.code",
      "position": [
        576,
        64
      ],
      "parameters": {
        "jsCode": "// 1) Read POST body (supports Webhook { body: {...} } or raw JSON)\nconst src = items?.[0]?.json ?? {};\nconst bodyRaw = (src.body ?? src ?? {});\nconst body = (typeof bodyRaw === 'string')\n  ? (() => { try { return JSON.parse(bodyRaw); } catch { return {}; } })()\n  : bodyRaw;\n\n// 2) Helpers\nfunction normalizeDomain(input = '') {\n  const s = String(input).trim();\n  if (!s) return '';\n  return s\n    .replace(/^https?:\\/\\//i, '') // remove protocol\n    .replace(/^www\\./i, '')       // remove www\n    .replace(/\\/+$/g, '');        // remove trailing slashes\n}\nfunction splitList(input) {\n  if (Array.isArray(input)) return input.map(String);\n  return String(input || '')\n    .split(/[,\\n\\r;]+/)\n    .map(s => s.trim())\n    .filter(Boolean);\n}\nfunction toGlobs(list) {\n  return splitList(list).map(p => (p.endsWith('*') ? p : `${p}*`));\n}\n\n// 3) Map incoming fields\nconst row = {\n  client_name:   body.client_name ?? body.name ?? '',\n  client_domain: body.client_domain ?? '',\n  competitors:   body.competitors ?? body.competitor ?? body.url ?? '',\n  include_paths: body.include_paths ?? '',\n  exclude_paths: body.exclude_paths ?? '',\n  max_pages:     body.max_pages ?? '',\n  crawl_depth:   body.crawl_depth ?? '',\n  notify_email:  body.notify_email ?? body.email ?? '',\n  processed:     (typeof body.processed === 'boolean'\n                    ? body.processed\n                    : String(body.processed ?? '').toLowerCase() === 'true'),\n  rowIndex:      body.rowIndex ?? null,\n};\n\n// 4) Early exit if sender marked it processed\nif (row.processed === true) return [];\n\n// 5) Build Apify fields\nconst competitorDomain = normalizeDomain(row.competitors);\nconst clientDomain     = normalizeDomain(row.client_domain);\n\nconst startUrls = competitorDomain\n  ? [{ url: `https://${competitorDomain}/`, method: 'GET' }]\n  : [];\n\nif (!startUrls.length) {\n  return [{ json: { error: 'NO_START_URLS', raw_competitors: row.competitors || '' } }];\n}\n\nconst includeArr = toGlobs(row.include_paths);\nconst excludeArr = toGlobs(row.exclude_paths);\n\nconst maxPages   = Number(row.max_pages)   || 20;\nconst crawlDepth = Number(row.crawl_depth) || 1;\n\n// 6) Output for next nodes\nreturn [{\n  json: {\n    client_name:       String(row.client_name || ''),\n    client_domain:     clientDomain,\n    competitor_domain: competitorDomain,\n    startUrls,\n    includeArr,\n    excludeArr,\n    max_pages_num:     maxPages,\n    crawl_depth_num:   crawlDepth,\n    notify_email:      String(row.notify_email || ''),\n    rowIndex:          row.rowIndex,\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "82bce0ee-a888-4e7e-9dc6-47bdcf3e18e9",
      "name": "경쟁사 웹사이트 크롤링",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        1024,
        -32
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "aYG0l9s7dbB7j3gbS",
          "cachedResultUrl": "https://console.apify.com/actors/aYG0l9s7dbB7j3gbS/input",
          "cachedResultName": "Website Content Crawler (apify/website-content-crawler)"
        },
        "timeout": {},
        "customBody": "={{ JSON.stringify({\n  crawlerType: \"cheerio\",\n  startUrls: $json.startUrls,                 \n  useSitemaps: false,\n  maxDepth: $json.crawl_depth_num  || 0,\n  maxRequestsPerCrawl: $json.max_pages_num || 20,\nmaxConcurrency:1,\n  respectRobotsTxtFile: true,\n  ignoreHttpsErrors: true,\n  proxyConfiguration: { useApifyProxy: true },\n  removeCookieWarnings: true,\n  removeElementsCssSelector: \"nav, footer, script, style, noscript, svg, img[src^='data:']\",\n  blockMedia: true,\n  saveMarkdown: true,\n  saveHtml: false,\n  saveFiles: false,\n  saveScreenshots: false\n}) }}\n"
      },
      "credentials": {
        "apifyApi": {
          "id": "Uzk0v4R6yNh8OxbO",
          "name": "Apify account"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d7eb2fc0-464d-450e-9be9-ac7e2e9488c3",
      "name": "크롤링된 데이터셋 가져오기",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1248,
        -32
      ],
      "parameters": {
        "url": "={{   \"https://api.apify.com/v2/datasets/\"   + ($json.data?.defaultDatasetId || $json.defaultDatasetId || \"auD8MlRMr6mZQpRS1\")   + \"/items?clean=true&format=json&offset=0&limit=1\" }}",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "9e970002-63b5-4f1b-8189-b59eb92a9471",
      "name": "페이지 메타데이터 추출",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        -32
      ],
      "parameters": {
        "jsCode": "// Renamed variables for clarity; behavior unchanged.\nconst sourceItem = items?.[0]?.json;\nif (!sourceItem) return [];\n\nconst markdownText = String(sourceItem.markdown || sourceItem.text || '');\nconst wordCount = markdownText.trim().split(/\\s+/).filter(Boolean).length;\n\nfunction getTitleFromMarkdown(markdown, url) {\n  const lines = markdown.split(/\\r?\\n/).map(line => line.trim());\n\n  const h1Line = lines.find(line => /^#\\s+/.test(line));\n  if (h1Line) return h1Line.replace(/^#\\s+/, '').trim();\n\n  const firstMeaningfulLine = lines.find(line => line.length > 0 && line.length < 120);\n  if (firstMeaningfulLine) return firstMeaningfulLine;\n\n  try {\n    const parsedUrl = new URL(url);\n    const pathSegments = parsedUrl.pathname.split('/').filter(Boolean);\n    return (pathSegments.pop() || parsedUrl.hostname).replace(/[-_]/g, ' ');\n  } catch {\n    return url;\n  }\n}\n\nreturn [{\n  json: {\n    page_url: sourceItem.url,\n    title: getTitleFromMarkdown(markdownText, sourceItem.url),\n    word_count: wordCount,\n    reading_time_min: Math.max(1, Math.ceil(wordCount / 200)),\n    excerpt: markdownText.slice(0, 600),\n    markdown: markdownText\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "7e929b2d-89d8-4a36-a13e-f82ae18f3f03",
      "name": "페이지 콘텐츠 분석",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1776,
        192
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "id": "qQGrvqnSPqWFH6I6",
          "name": "Google Gemini(PaLM) Api account 5"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f8c1643b-4382-49c0-9ec3-35876bd52eb2",
      "name": "Gemini JSON 파싱 및 정규화",
      "type": "n8n-nodes-base.code",
      "position": [
        2048,
        -32
      ],
      "parameters": {
        "jsCode": "\nfunction stripCodeFences(text = \"\") {\n  \n  return String(text)\n    .replace(/^\\s*```(?:json)?\\s*/i, \"\")\n    .replace(/\\s*```\\s*$/i, \"\")\n    .trim();\n}\n\nfunction safeParseModelJson(payload) {\n  \n  if (payload && (payload.page_url || payload.main_topics || payload.key_entities)) return payload;\n\n  let raw = payload?.output ?? payload;\n  if (typeof raw !== \"string\") raw = JSON.stringify(raw ?? {});\n  raw = stripCodeFences(raw);\n\n  let obj;\n  try { obj = JSON.parse(raw); } catch {}\n\n\n  if (Array.isArray(obj)) {\n    if (obj[0]?.output) {\n      try { obj = JSON.parse(stripCodeFences(obj[0].output)); } catch { obj = obj[0] || {}; }\n    } else {\n      obj = obj[0] || {};\n    }\n  } else if (obj && typeof obj === \"object\" && typeof obj.output === \"string\") {\n    try { obj = JSON.parse(stripCodeFences(obj.output)); } catch {}\n  }\n\n  return obj || {};\n}\n\nfunction normalizeTopicTree(nodes = [], level = 1) {\n  return nodes.map(node => ({\n    topic: String(node?.topic ?? \"\"),\n    level: Number(node?.level) || level,\n    subtopics: normalizeTopicTree(node?.subtopics || [], (Number(node?.level) || level) + 1),\n  }));\n}\n\nfunction toTopicTree(modelObj) {\n  let t = modelObj.main_topics;\n  if (typeof t === \"string\") {\n    try { t = JSON.parse(t); } catch { t = []; }\n  }\n  if (!Array.isArray(t)) t = [];\n  return normalizeTopicTree(t, 1);\n}\n\nfunction toBulletLines(tree, indent = \"\") {\n  const lines = [];\n  for (const node of tree) {\n    const text = String(node.topic || \"\").trim();\n    if (text) lines.push(`${indent}- ${text}`);\n    if (node.subtopics?.length) lines.push(...toBulletLines(node.subtopics, indent + \"  \"));\n  }\n  return lines;\n}\n\nfunction parseEntitiesToBullets(value) {\n  let arr = value;\n\n  if (typeof arr === \"string\") {\n    const s = arr.trim();\n    if (/^- /m.test(s)) {\n      // Already looks like \"- item\" lines\n      arr = s.split(/\\r?\\n/).map(l => l.replace(/^\\s*-\\s*/, \"\").trim()).filter(Boolean);\n    } else {\n      try { arr = JSON.parse(s); }\n      catch { arr = s.split(\",\").map(x => x.trim()).filter(Boolean); }\n    }\n  }\n\n  if (!Array.isArray(arr)) arr = [];\n  return arr.length ? arr.map(e => `- ${String(e)}`).join(\"\\n\") : \"- (none)\";\n}\n\nfunction chooseUrl(...candidates) {\n  for (const c of candidates) {\n    const v = String(c ?? \"\").trim();\n    if (v && !/^n\\/?a$/i.test(v)) return v; // reject \"N/A\", \"n/a\"\n  }\n  return \"\";\n}\n\n// ---------- main ----------\nconst inputPayload = items?.[0]?.json ?? {};\nconst modelObj     = safeParseModelJson(inputPayload);\n\n// Build bullets\nconst topicTree        = toTopicTree(modelObj);\nconst mainTopicsFlat   = topicTree.length ? toBulletLines(topicTree).join(\"\\n\") : \"- (none)\";\nconst keyEntitiesFlat  = parseEntitiesToBullets(modelObj.key_entities);\n\n// Prefer the true URL from \"Extract Page Metadata\"\nlet urlFromMeta;\ntry {\n  urlFromMeta =\n    $items(\"Extract Page Metadata\", 0, 0)?.json?.page_url ||\n    $items(\"Extract Page Metadata\", 0, 0)?.json?.url;\n} catch {}\n\nconst pageUrl = chooseUrl(\n  urlFromMeta,\n  inputPayload?.page_url,\n  modelObj?.page_url\n);\n\n// Output\nreturn [{\n  json: {\n    page_url: pageUrl,\n    main_topics_flat: mainTopicsFlat,\n    key_entities_flat: keyEntitiesFlat,\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "e5c2649e-d2ea-49a0-a3ad-5f9916843da2",
      "name": "시트 이름 도출",
      "type": "n8n-nodes-base.code",
      "position": [
        2272,
        -32
      ],
      "parameters": {
        "jsCode": "\nfunction toSheetName(raw) {\n  let s = String(raw || '').trim();\n  if (!s) return 'Page';\n  if (!/^https?:\\/\\//i.test(s)) s = 'https://' + s;\n\n  try {\n    const u = new URL(s);\n    const host = u.hostname.replace(/^www\\./, '');\n    let path = (u.pathname || '/')\n      .replace(/\\/+/g, '/')\n      .replace(/^\\/|\\/$/g, '');\n    let name = path ? `${host}_${path}` : host;\n    name = name.replace(/[:\\\\\\/\\?\\*\\[\\]]/g, '·').replace(/\\s+/g, ' ').trim();\n    return name || 'Page';\n  } catch {\n    let name = s.replace(/^https?:\\/\\//i, '').replace(/[:\\\\\\/\\?\\*\\[\\]]/g, '·').trim();\n    return name || 'Page';\n  }\n}\n\n// Make N random digits as a string (e.g., \"48291\")\nfunction randDigits(n = 5) {\n  let out = '';\n  for (let i = 0; i < n; i++) out += Math.floor(Math.random() * 10);\n  return out;\n}\n\nconst MAX_LEN = 90;        // Sheets tab name limit\nconst DIGITS = 5;          // how many random digits to append\n\nreturn items.map(({ json }) => {\n  const url = json.page_url ?? json.url ?? json.pageUrl ?? '';\n  const base = toSheetName(url);\n\n  const suffix = '_' + randDigits(DIGITS);          \n  const roomForBase = Math.max(0, MAX_LEN - suffix.length);\n  const safeBase = base.length > roomForBase ? base.slice(0, roomForBase) : base;\n\n  const sheet_name = `${safeBase}${suffix}`;\n\n  return {\n    json: {\n      ...json,\n      sheet_name,\n      _sheet_name_src: url \n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "7b85f71d-7bdf-4de2-a572-494347582699",
      "name": "병합",
      "type": "n8n-nodes-base.merge",
      "position": [
        2720,
        -16
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "6182edc0-197d-40b6-bdd0-a00b6d0fa73e",
      "name": "요청 데이터 저장",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1024,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "max_pages": "={{ $json.max_pages_num }}",
            "client_name": "={{ $json.client_name }}",
            "competitors": "={{ $json.competitor_domain }}",
            "crawl_depth": "={{ $json.crawl_depth_num }}",
            "notify_email": "={{ $json.notify_email }}",
            "exclude_paths": "={{ $json.excludeArr }}",
            "include_paths": "={{ $json.includeArr }}"
          },
          "schema": [
            {
              "id": "client_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "client_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "competitors",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "competitors",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "include_paths",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "include_paths",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exclude_paths",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "exclude_paths",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "max_pages",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "max_pages",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "crawl_depth",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "crawl_depth",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "notify_email",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "notify_email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ/edit#gid=0",
          "cachedResultName": "CONFIG"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ/edit?usp=drivesdk",
          "cachedResultName": "Content Gap Analyzer"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "wHDA0XakCCVOLVNe",
          "name": "Google Sheets account 2"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2b28b4f7-e07d-4d14-950c-61a2d36fdb34",
      "name": "데이터 존재 여부 확인",
      "type": "n8n-nodes-base.if",
      "position": [
        800,
        64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c87f5a6e-e9c8-4c57-a5b3-2c77371cd529",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.startUrls[0].method }}",
              "rightValue": "GET"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7273236a-42f6-4c62-8f79-52e039e15433",
      "name": "이메일 전송 콘텐츠 확인",
      "type": "n8n-nodes-base.if",
      "position": [
        3392,
        -16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f1cdaf14-a4af-4ec9-8db2-4a8ddb78f4c4",
              "operator": {
                "type": "string",
                "operation": "regex"
              },
              "leftValue": "={{ $json.page_url }}",
              "rightValue": "^https?://"
            },
            {
              "id": "8600a236-03c6-45db-91fe-89f93926c97e",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.main_topics }}",
              "rightValue": ""
            },
            {
              "id": "ba4c3349-2b5c-4122-873e-fd93e5f3b944",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.key_words }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "c97679a0-efc5-43ab-b603-c40173c6d4e7",
      "name": "수집된 데이터 저장",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3168,
        -16
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [
            {
              "id": "page_url",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "page_url",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "main_topics",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "main_topics",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "key_words",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "key_words",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Derive Sheet Name').item.json.sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ/edit?usp=drivesdk",
          "cachedResultName": "Content Gap Analyzer"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "wHDA0XakCCVOLVNe",
          "name": "Google Sheets account 2"
        }
      },
      "executeOnce": true,
      "typeVersion": 4.7
    },
    {
      "id": "ecec493c-7b3b-4746-90f7-1b28ce224d9c",
      "name": "데이터 시트 생성",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2512,
        64
      ],
      "parameters": {
        "title": "={{ $json.sheet_name }}",
        "options": {},
        "operation": "create",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1OvrhykXjzBI0_VqXurrQOMMtvBWfBVlttZVI1LhcRoQ/edit?usp=drivesdk",
          "cachedResultName": "Content Gap Analyzer"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "wHDA0XakCCVOLVNe",
          "name": "Google Sheets account 2"
        }
      },
      "executeOnce": false,
      "notesInFlow": false,
      "retryOnFail": false,
      "typeVersion": 4.7
    },
    {
      "id": "0964d490-2039-4658-be5f-c9b374fab9dc",
      "name": "보고서 전송",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3616,
        -32
      ],
      "webhookId": "1d1f6479-dd01-4dee-97cc-ff1a3b706dcb",
      "parameters": {
        "sendTo": "={{ $('Prepare Apify Input').item.json.notify_email }}",
        "message": "=<div style=\"font-family: Arial, sans-serif; color: #333;\">\n  <h2 style=\"color:#4CAF50;\">📊 Competitor SEO Content Analysis Report</h2>\n\n  <p><b>Page URL:</b> <a href=\"{{ $json.page_url }}\" target=\"_blank\">{{ $json.page_url }}</a></p>\n\n  <h3>Main Topics</h3>\n  <pre style=\"background:#f9f9f9; padding:10px; border:1px solid #ddd; white-space:pre-wrap; margin:0;\">\n{{ $json.main_topics }}\n  </pre>\n\n  <h3>Keywords Identified</h3>\n  <pre style=\"background:#f9f9f9; padding:10px; border:1px solid #ddd; white-space:pre-wrap; margin:0;\">\n{{ $json.key_words }}\n  </pre>\n</div>",
        "options": {},
        "subject": "=SEO Audit Report: {{ $json.page_url }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "jkKHvU2Pb9X5WJk5",
          "name": "Gmail account"
        }
      },
      "executeOnce": true,
      "typeVersion": 2.1
    },
    {
      "id": "f5ee629d-0845-4680-9104-672f7e2a3570",
      "name": "스티키 노트2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        960,
        336
      ],
      "parameters": {
        "color": 5,
        "height": 112,
        "content": "### Save Data Of The request\nAppend sheet.\nUse **Google Sheets OAuth2** credential"
      },
      "typeVersion": 1
    },
    {
      "id": "b846b79a-f3ab-4b05-9bbe-41ecf82f8626",
      "name": "스티키 노트3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        -192
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 144,
        "content": "### Crawl Competitor Website\nRun apify/website-content-crawler with startUrls; saveMarkdown: true.\nCredentials: Use **Apify API** credential."
      },
      "typeVersion": 1
    },
    {
      "id": "a684c3ba-f7a2-446f-9f27-5fc7dade6d3c",
      "name": "스티키 노트4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1680,
        320
      ],
      "parameters": {
        "color": 5,
        "width": 272,
        "height": 112,
        "content": "### Analyze Page Send markdown; expect strict JSON back.\nCredentials:  \nUse **Google Gemini/PaLM** credential."
      },
      "typeVersion": 1
    },
    {
      "id": "0a3c9884-2fe0-4759-941f-7fe2af68b682",
      "name": "스티키 노트5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3536,
        128
      ],
      "parameters": {
        "color": 5,
        "width": 256,
        "height": 128,
        "content": "### Send report \nSend Email\nCredentials: Use **Gmail OAuth2** credential. (required)."
      },
      "typeVersion": 1
    },
    {
      "id": "81fa829e-90ef-41a4-aa23-c65887297f6d",
      "name": "스티키 노트1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -928
      ],
      "parameters": {
        "color": 3,
        "width": 336,
        "height": 304,
        "content": "\n## Benefits\n- **Competitor mapping at scale**  Automatically map sites into hierarchical topics and entities.\n- **Data-driven content strategy**  Identify gaps, weak spots, and opportunities to stand out.\n- **Seamless integration**  Results flow straight into Google Sheets for filtering, charting, or export.\n- **Time & resource savings**  Eliminate copy-paste research and focus on strategy.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "df5d7ff4-6e19-48fd-b3ec-7e9a302a7d81",
      "name": "스티키 노트6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        912,
        -928
      ],
      "parameters": {
        "color": 6,
        "width": 288,
        "height": 176,
        "content": "## Target audience\n- SEO specialists and digital marketers\n- Content strategists and copywriters\n- Agencies running content audits\n- SaaS startups monitoring competition\n- E-commerce teams benchmarking rivals"
      },
      "typeVersion": 1
    },
    {
      "id": "b74a1d37-14b2-4cf4-8b1e-5ffc0c54ec84",
      "name": "스티키 노트7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1280,
        -928
      ],
      "parameters": {
        "color": 5,
        "width": 406,
        "height": 176,
        "content": "## Required APIs\n- Google Sheets credentials (trigger & save)\n- Apify API token (crawler)\n- Gemini (Google Generative AI) key (content parsing)\n- Gmail OAuth2 credentials (send report emails)"
      },
      "typeVersion": 1
    },
    {
      "id": "c8dde663-90f0-46e7-bebe-de63a7c58f74",
      "name": "스티키 노트8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        -928
      ],
      "parameters": {
        "color": 2,
        "width": 496,
        "height": 176,
        "content": "## Easy customization\n- **Competitor domains:** Update in the Google Sheets config.\n- **Crawl depth & limits:** Adjust `max_pages_num` and `crawl_depth_num`.\n- **Output format:** Modify the Code node to add or remove Google Sheets columns.\n- **Delivery channels:** Add Slack or Email nodes for instant audit reports."
      },
      "typeVersion": 1
    },
    {
      "id": "f3181117-2221-4b73-9632-2572ab4f2a89",
      "name": "스티키 노트9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2448,
        208
      ],
      "parameters": {
        "color": 5,
        "width": 224,
        "height": 112,
        "content": "### Create sheet for the data\nCredentials:\nUse **Google Sheets OAuth2** credential."
      },
      "typeVersion": 1
    },
    {
      "id": "874709c8-edd9-4084-b3bd-ad925b039f40",
      "name": "스티키 노트10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        -48
      ],
      "parameters": {
        "color": 5,
        "width": 208,
        "height": 208,
        "content": "### Webhook — Start Here\n\n**Production URL**\nCopy the **Production** URL from the Webhook node and share it with your form/app.\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "00661d71-a7b1-485e-bff7-a1888df54b85",
      "name": "스티키 노트11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        416,
        -496
      ],
      "parameters": {
        "color": 5,
        "width": 448,
        "height": 336,
        "content": "### Submission form\n**POST (required)**\n- `competitor` (domain or URL; aliases: `competitors`, `url`)\n- `notify_email` (recipient; alias: `email`)\n\n**Optional**\n- `include_paths` (e.g. `/blog/`, `/services/*`)\n- `exclude_paths` (e.g. `/login`, `/wp-admin/*`)\n- `max_pages` (default 20)\n- `crawl_depth` (default 1)\n\n**Webhook URL**\nSet `webhookUrl` to your n8n endpoint (e.g. `https://<host>/webhook/competitors`).se '/webhook-test/competitors'"
      },
      "typeVersion": 1
    },
    {
      "id": "cd5b853c-8331-442b-b4c4-d772c6bdc4f8",
      "name": "시작하기",
      "type": "n8n-nodes-base.webhook",
      "position": [
        352,
        -32
      ],
      "webhookId": "300e7628-acda-4e87-ad89-6179f6d89260",
      "parameters": {
        "path": "competitors",
        "options": {},
        "responseMode": "responseNode",
        "multipleMethods": true
      },
      "typeVersion": 2.1
    },
    {
      "id": "be10836c-5727-4607-9dfb-12d50ad1f12b",
      "name": "제출 양식",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        576,
        -128
      ],
      "parameters": {
        "options": {},
        "respondWith": "text",
        "responseBody": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <title>Competitor Crawl Request</title>\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n  <style>\n    :root{\n      --bg-0:#0b1220;\n      --bg-1:#0f172a;\n      --bg-2:#111827;\n      --card:#0b1220;\n      --text:#e5e7eb;\n      --muted:#94a3b8;\n      --line:#1f2937;\n      --accent:#7c3aed;      /* violet */\n      --accent-2:#06b6d4;    /* cyan */\n      --ok:#10b981;          /* green */\n      --err:#ef4444;         /* red */\n    }\n    *{box-sizing:border-box}\n    html,body{height:100%}\n    body{\n      margin:0;\n      background:\n        radial-gradient(1200px 600px at 20% -10%, rgba(124,58,237,.18), transparent 60%),\n        radial-gradient(1000px 400px at 120% 10%, rgba(6,182,212,.20), transparent 60%),\n        linear-gradient(180deg, #0b1220, #0b1220 60%, #0a1020 100%);\n      color:var(--text);\n      font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial, \"Noto Sans\", \"Apple Color Emoji\",\"Segoe UI Emoji\";\n      display:flex; align-items:center; justify-content:center;\n      padding:24px;\n    }\n    .card{\n      width:100%;\n      max-width: 720px;\n      background: linear-gradient(180deg, rgba(255,255,255,.03), rgba(255,255,255,.01));\n      border:1px solid var(--line);\n      border-radius: 16px;\n      box-shadow: 0 10px 30px rgba(0,0,0,.45), inset 0 1px 0 rgba(255,255,255,.03);\n      backdrop-filter: blur(8px);\n      overflow: hidden;\n    }\n    .card header{\n      padding:20px 24px;\n      border-bottom:1px solid var(--line);\n      display:flex; align-items:center; gap:12px;\n      background: linear-gradient(180deg, rgba(124,58,237,.15), rgba(124,58,237,.02));\n    }\n    .logo{\n      width:36px; height:36px; border-radius:10px;\n      background: conic-gradient(from 210deg, var(--accent), var(--accent-2));\n      box-shadow: 0 0 0 2px rgba(255,255,255,.06), 0 8px 16px rgba(124,58,237,.2);\n    }\n    h1{font-size:1.15rem; margin:0}\n    .sub{font-size:.9rem; color:var(--muted); margin-top:2px}\n    form{padding:20px 24px 24px}\n    .grid{\n      display:grid;\n      grid-template-columns: 1fr;\n      gap:16px;\n    }\n    @media (min-width: 720px){\n      .grid{ grid-template-columns: 1fr 1fr; }\n      .grid .full{ grid-column: 1 / -1; }\n    }\n    label{\n      display:block; font-size:.92rem; font-weight:600; margin-bottom:8px; color:#c7d2fe;\n    }\n    input, select, textarea{\n      width:100%;\n      background:#0d1426;\n      color:var(--text);\n      border:1px solid #1e293b;\n      border-radius:10px;\n      padding:12px 12px;\n      font-size: 0.98rem;\n      outline:none;\n      transition: border .15s, box-shadow .15s, transform .02s;\n    }\n    input::placeholder, textarea::placeholder{ color:#6b7280 }\n    input:focus, select:focus, textarea:focus{\n      border-color: var(--accent);\n      box-shadow: 0 0 0 3px rgba(124,58,237,.2);\n    }\n    select[multiple]{\n      min-height:132px;\n      padding:10px;\n    }\n    small.help{ display:block; color:var(--muted); margin-top:6px; }\n    .row{\n      display:flex; gap:10px; align-items:center; margin-top:6px;\n    }\n    .row input{ flex:1 }\n    .pill{\n      display:inline-flex; align-items:center; gap:8px;\n      padding:10px 14px; border-radius:999px;\n      border:1px solid #233046; background:#0e1629;\n      font-weight:700; letter-spacing:.2px;\n      color:#e9d5ff;\n      cursor:pointer; user-select:none;\n      transition: transform .02s, background .15s, border .15s;\n    }\n    .pill:hover{ background:#121b31; border-color:#2a3a57 }\n    .submit{\n      display:flex; gap:12px; align-items:center; justify-content:flex-end;\n      padding:18px 24px; border-top:1px solid var(--line);\n      background: linear-gradient(180deg, rgba(6,182,212,.08), rgba(6,182,212,.02));\n    }\n    button{\n      all:unset;\n      background: linear-gradient(90deg, var(--accent), var(--accent-2));\n      padding:12px 18px; border-radius:12px; cursor:pointer; font-weight:700;\n      box-shadow: 0 10px 22px rgba(124,58,237,.25);\n    }\n    button[disabled]{ opacity:.7; cursor:not-allowed; box-shadow:none }\n    .msg{ padding:12px 16px; font-weight:600; }\n    .success{ color: var(--ok); }\n    .error{ color: var(--err); }\n    .inline-note{ font-size:.85rem; color:var(--muted); margin-left:10px }\n  </style>\n</head>\n<body>\n  <div class=\"card\" role=\"region\" aria-label=\"Competitor Crawl Request\">\n    <header>\n      <div class=\"logo\" aria-hidden=\"true\"></div>\n      <div>\n        <h1>Competitor Crawl Request</h1>\n        <div class=\"sub\">Send a domain and optional scoping rules for the crawl</div>\n      </div>\n    </header>\n\n    <form id=\"requestForm\" novalidate>\n      <div class=\"grid\">\n        <div class=\"full\">\n          <label for=\"competitors\">Competitor URL / Domain</label>\n          <input id=\"competitors\" name=\"competitors\" type=\"text\" required placeholder=\"https://example.com or example.com\" />\n          <small class=\"help\">A full URL or bare domain is fine — we’ll normalize it.</small>\n        </div>\n\n        <div>\n          <label for=\"name\">Your Name</label>\n          <input id=\"name\" name=\"name\" type=\"text\" required placeholder=\"Your name…\" autocomplete=\"name\" />\n        </div>\n\n        <div>\n          <label for=\"email\">Email (for report)</label>\n          <input id=\"email\" name=\"email\" type=\"email\" required placeholder=\"you@domain.com\" autocomplete=\"email\" inputmode=\"email\" />\n          <small class=\"help\">We’ll email the summary here.</small>\n        </div>\n\n        <div class=\"full\">\n          <label for=\"include_paths\">Include paths (multi-select)</label>\n          <select id=\"include_paths\" multiple>\n            <option value=\"/\">/</option>\n            <option value=\"/blog/\">/blog/</option>\n            <option value=\"/services/\">/services/</option>\n            <option value=\"/products/\">/products/</option>\n            <option value=\"/news/\">/news/</option>\n            <option value=\"/portfolio/\">/portfolio/</option>\n          </select>\n          <div class=\"row\">\n            <input id=\"include_custom\" type=\"text\" placeholder=\"Custom paths (comma-separated, e.g. /guide/, /docs/ )\" />\n            <span class=\"pill\" id=\"add_include\">+ Add</span>\n          </div>\n          <small class=\"help\">Hold Ctrl/⌘ to select multiple. Custom items are appended automatically.</small>\n        </div>\n\n        <div class=\"full\">\n          <label for=\"exclude_paths\">Exclude paths (multi-select)</label>\n          <select id=\"exclude_paths\" multiple>\n            <option value=\"/privacy\">/privacy</option>\n            <option value=\"/terms\">/terms</option>\n            <option value=\"/login\">/login</option>\n            <option value=\"/cart\">/cart</option>\n            <option value=\"/checkout\">/checkout</option>\n            <option value=\"/wp-admin\">/wp-admin</option>\n            <option value=\"/tag/\">/tag/</option>\n            <option value=\"/category/\">/category/</option>\n            <option value=\"/feed\">/feed</option>\n          </select>\n          <div class=\"row\">\n            <input id=\"exclude_custom\" type=\"text\" placeholder=\"Custom paths (comma-separated, e.g. /search, /admin )\" />\n            <span class=\"pill\" id=\"add_exclude\">+ Add</span>\n          </div>\n          <small class=\"help\">Use this to skip utility/low-value areas.</small>\n        </div>\n\n        <div>\n          <label for=\"max_pages\">Max pages</label>\n          <select id=\"max_pages\">\n            <option value=\"5\">5</option>\n            <option value=\"10\">10</option>\n            <option value=\"20\" selected>20</option>\n            <option value=\"50\">50</option>\n            <option value=\"100\">100</option>\n            <option value=\"200\">200</option>\n          </select>\n          <span class=\"inline-note\">Default 20</span>\n        </div>\n\n        <div>\n          <label for=\"crawl_depth\">Crawl depth</label>\n          <select id=\"crawl_depth\">\n            <option value=\"0\">0 (only start URL)</option>\n            <option value=\"1\" selected>1</option>\n            <option value=\"2\">2</option>\n            <option value=\"3\">3</option>\n          </select>\n          <span class=\"inline-note\">Default 1</span>\n        </div>\n      </div>\n\n      <div class=\"submit\">\n        <div id=\"response\" class=\"msg\" aria-live=\"polite\"></div>\n        <button id=\"submitBtn\" type=\"submit\">Send Request</button>\n      </div>\n    </form>\n  </div>\n\n  <script>\n    const $ = (id) => document.getElementById(id);\n\n    function showMsg(text, type) {\n      const el = $('response');\n      el.className = 'msg ' + (type || '');\n      el.textContent = text;\n    }\n\n    function normalizeUrl(input) {\n      const s = (input || '').trim();\n      if (!s) return '';\n      return /^https?:\\/\\//i.test(s) ? s : `https://${s}`;\n    }\n\n    function selectedValues(selectEl) {\n      return Array.from(selectEl.options)\n        .filter(o => o.selected)\n        .map(o => o.value.trim())\n        .filter(Boolean);\n    }\n\n    function parseCustom(inputEl) {\n      return (inputEl.value || '')\n        .split(',')\n        .map(s => s.trim())\n        .filter(Boolean);\n    }\n\n    function addCustomToSelect(inputEl, selectEl) {\n      parseCustom(inputEl).forEach(v => {\n        const opt = document.createElement('option');\n        opt.value = v;\n        opt.textContent = v;\n        opt.selected = true;\n        selectEl.appendChild(opt);\n      });\n      inputEl.value = '';\n    }\n\n    // Wire add buttons\n    $('add_include').addEventListener('click', () => addCustomToSelect($('include_custom'), $('include_paths')));\n    $('add_exclude').addEventListener('click', () => addCustomToSelect($('exclude_custom'), $('exclude_paths')));\n\n    $('requestForm').addEventListener('submit', async (e) => {\n      e.preventDefault();\n      showMsg('', '');\n\n      if (!e.target.checkValidity()) {\n        e.target.reportValidity();\n        return;\n      }\n\n      const name  = $('name').value.trim();\n      const email = $('email').value.trim();\n      const competitors = normalizeUrl($('competitors').value.trim());\n\n      const emailOk = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);\n      if (!emailOk) { $('email').focus(); return showMsg('❌ Please enter a valid email.', 'error'); }\n\n      if (!competitors) { $('competitors').focus(); return showMsg('❌ Please enter a competitor URL.', 'error'); }\n\n      // Merge dropdown selections + any custom text entries\n      const includeSel = selectedValues($('include_paths'));\n      const excludeSel = selectedValues($('exclude_paths'));\n      const includeCustom = parseCustom($('include_custom'));\n      const excludeCustom = parseCustom($('exclude_custom'));\n\n      const include_paths = [...includeSel, ...includeCustom].join(', ');\n      const exclude_paths = [...excludeSel, ...excludeCustom].join(', ');\n\n      const max_pages   = $('max_pages').value;\n      const crawl_depth = $('crawl_depth').value;\n\n      const submitBtn = $('submitBtn');\n      submitBtn.setAttribute('disabled','true');\n      submitBtn.textContent = 'Sending…';\n\n      try {\n        const webhookUrl = 'https://n8nworkflow.eu/webhook-test/competitors'; // use production /webhook/... when you deploy\n        const res = await fetch(webhookUrl, {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({\n            name,\n            email,\n            competitors,\n            include_paths,\n            exclude_paths,\n            max_pages,\n            crawl_depth\n          })\n        });\n\n        if (res.ok) {\n          showMsg('✅ Request sent. We’ll email you when it’s processed.', 'success');\n          e.target.reset();\n        } else {\n          const txt = await res.text().catch(() => '');\n          showMsg('❌ Failed to send. ' + (txt || ''), 'error');\n        }\n      } catch (err) {\n        showMsg('❌ Network error. Please try again.', 'error');\n      } finally {\n        submitBtn.removeAttribute('disabled');\n        submitBtn.textContent = 'Send Request';\n      }\n    });\n  </script>\n</body>\n</html>"
      },
      "executeOnce": false,
      "retryOnFail": true,
      "typeVersion": 1.4
    },
    {
      "id": "76b234af-da62-4017-a648-e5a8d7a61c51",
      "name": "시트 행 준비",
      "type": "n8n-nodes-base.set",
      "position": [
        2944,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "367b45c6-c47d-43de-ae52-ea269cdbe938",
              "name": "page_url",
              "type": "string",
              "value": "={{ $('Parse and Normalize Gemini JSON').item.json.page_url }}"
            },
            {
              "id": "420d1ace-2bb3-4fbf-ada2-9301ca570f9a",
              "name": "main_topics",
              "type": "string",
              "value": "={{ $('Parse and Normalize Gemini JSON').item.json.main_topics_flat }}"
            },
            {
              "id": "707356b5-ae9f-4706-820d-213916363049",
              "name": "key_words",
              "type": "string",
              "value": "={{ $('Parse and Normalize Gemini JSON').item.json.key_entities_flat }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "timezone": "Europe/Helsinki",
    "callerPolicy": "workflowsFromSameOwner",
    "executionOrder": "v1"
  },
  "versionId": "30265337-2486-4efa-90c8-7dfb0cca682e",
  "connections": {
    "7b85f71d-7bdf-4de2-a572-494347582699": {
      "main": [
        [
          {
            "node": "76b234af-da62-4017-a648-e5a8d7a61c51",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8d912fd2-61b3-41df-9631-c7eaf6050bc9": {
      "main": [
        [
          {
            "node": "f8c1643b-4382-49c0-9ec3-35876bd52eb2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "cd5b853c-8331-442b-b4c4-d772c6bdc4f8": {
      "main": [
        [
          {
            "node": "be10836c-5727-4607-9dfb-12d50ad1f12b",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "a9a4fa59-bc0a-4175-afd8-46855bb271d3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "be10836c-5727-4607-9dfb-12d50ad1f12b": {
      "main": [
        []
      ]
    },
    "e5c2649e-d2ea-49a0-a3ad-5f9916843da2": {
      "main": [
        [
          {
            "node": "ecec493c-7b3b-4746-90f7-1b28ce224d9c",
            "type": "main",
            "index": 0
          },
          {
            "node": "7b85f71d-7bdf-4de2-a572-494347582699",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "76b234af-da62-4017-a648-e5a8d7a61c51": {
      "main": [
        [
          {
            "node": "c97679a0-efc5-43ab-b603-c40173c6d4e7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a9a4fa59-bc0a-4175-afd8-46855bb271d3": {
      "main": [
        [
          {
            "node": "2b28b4f7-e07d-4d14-950c-61a2d36fdb34",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "7e929b2d-89d8-4a36-a13e-f82ae18f3f03": {
      "ai_languageModel": [
        [
          {
            "node": "8d912fd2-61b3-41df-9631-c7eaf6050bc9",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "7273236a-42f6-4c62-8f79-52e039e15433": {
      "main": [
        [
          {
            "node": "0964d490-2039-4658-be5f-c9b374fab9dc",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "9e970002-63b5-4f1b-8189-b59eb92a9471": {
      "main": [
        [
          {
            "node": "8d912fd2-61b3-41df-9631-c7eaf6050bc9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d7eb2fc0-464d-450e-9be9-ac7e2e9488c3": {
      "main": [
        [
          {
            "node": "9e970002-63b5-4f1b-8189-b59eb92a9471",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2b28b4f7-e07d-4d14-950c-61a2d36fdb34": {
      "main": [
        [
          {
            "node": "82bce0ee-a888-4e7e-9dc6-47bdcf3e18e9",
            "type": "main",
            "index": 0
          },
          {
            "node": "6182edc0-197d-40b6-bdd0-a00b6d0fa73e",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c97679a0-efc5-43ab-b603-c40173c6d4e7": {
      "main": [
        [
          {
            "node": "7273236a-42f6-4c62-8f79-52e039e15433",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "82bce0ee-a888-4e7e-9dc6-47bdcf3e18e9": {
      "main": [
        [
          {
            "node": "d7eb2fc0-464d-450e-9be9-ac7e2e9488c3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6182edc0-197d-40b6-bdd0-a00b6d0fa73e": {
      "main": [
        []
      ]
    },
    "ecec493c-7b3b-4746-90f7-1b28ce224d9c": {
      "main": [
        [
          {
            "node": "7b85f71d-7bdf-4de2-a572-494347582699",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "f8c1643b-4382-49c0-9ec3-35876bd52eb2": {
      "main": [
        [
          {
            "node": "e5c2649e-d2ea-49a0-a3ad-5f9916843da2",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
자주 묻는 질문

이 워크플로우를 어떻게 사용하나요?

위의 JSON 구성 코드를 복사하여 n8n 인스턴스에서 새 워크플로우를 생성하고 "JSON에서 가져오기"를 선택한 후, 구성을 붙여넣고 필요에 따라 인증 설정을 수정하세요.

이 워크플로우는 어떤 시나리오에 적합한가요?

고급 - 기타, AI 요약, 멀티모달 AI

유료인가요?

이 워크플로우는 완전히 무료이며 직접 가져와 사용할 수 있습니다. 다만, 워크플로우에서 사용하는 타사 서비스(예: OpenAI API)는 사용자 직접 비용을 지불해야 할 수 있습니다.

워크플로우 정보
난이도
고급
노드 수30
카테고리3
노드 유형13
난이도 설명

고급 사용자를 위한 16+개 노드의 복잡한 워크플로우

외부 링크
n8n.io에서 보기

이 워크플로우 공유

카테고리

카테고리: 34