{
  "id": "IG9AfzIq3yAeIBGf",
  "meta": {
    "instanceId": "9239289f4ac5af7b996edef620e4bf7d2f9831e5f716593db80b14e930575f8f",
    "templateCredsSetupCompleted": true
  },
  "name": "Auto-Audit SEO Traffic Drops with AI & GSC(Google Search Console)",
  "tags": [],
  "nodes": [
    {
      "id": "09023769-87ad-49c1-9e86-4f64b295619e",
      "name": "Weekly Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        64,
        136
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "24b6bdbe-3923-4699-a2ef-89a07029f150",
      "name": "📝 Edit Me: Config",
      "type": "n8n-nodes-base.set",
      "position": [
        288,
        136
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "target_site_property",
              "value": "https://www.example.com/"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "ff0a32fa-18ef-4636-a93d-35475166e019",
      "name": "GSC: Compare Period",
      "type": "n8n-nodes-google-search-console.googleSearchConsole",
      "position": [
        512,
        136
      ],
      "parameters": {
        "operation": "comparePageInsights",
        "siteUrlCompare": "={{ $('📝 Edit Me: Config').first().json.target_site_property }}"
      },
      "credentials": {
        "googleSearchConsoleOAuth2Api": {
          "id": "credential-id",
          "name": "googleSearchConsoleOAuth2Api Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4339d57f-75af-4deb-95d7-d884a1e125f0",
      "name": "Filter: Drops",
      "type": "n8n-nodes-base.filter",
      "position": [
        736,
        136
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "filter_clicks",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "leftValue": "={{ $json.clicks_diff }}",
              "rightValue": 0
            },
            {
              "id": "filter_pos",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.pos_diff }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "45baa747-a605-41dd-8c06-4db378d1904d",
      "name": "Loop Pages",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        960,
        136
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "3ea53226-8917-48f9-ae39-2427ea0e286f",
      "name": "Wait 1s",
      "type": "n8n-nodes-base.wait",
      "position": [
        1184,
        64
      ],
      "webhookId": "71cb607c-9192-4a93-b742-6e4883483f2f",
      "parameters": {
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "ba6e71c7-6513-431e-9f0a-8c22533f3264",
      "name": "GSC: Get Queries",
      "type": "n8n-nodes-google-search-console.googleSearchConsole",
      "position": [
        1408,
        64
      ],
      "parameters": {
        "filters": {
          "filter": [
            {
              "operator": "equals",
              "dimension": "page",
              "expression": "={{ $('Loop Pages').first().json.page }}"
            }
          ]
        },
        "siteUrl": "={{ $('📝 Edit Me: Config').first().json.target_site_property }}",
        "operation": "getPageInsights",
        "dimensions": [
          "page",
          "query"
        ]
      },
      "credentials": {
        "googleSearchConsoleOAuth2Api": {
          "id": "credential-id",
          "name": "googleSearchConsoleOAuth2Api Credential"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f1e0d255-faaa-4162-8cbb-b7914d569235",
      "name": "Format Queries",
      "type": "n8n-nodes-base.code",
      "position": [
        1632,
        64
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nif (items.length === 0) return { json: { formatted_data: \"No Data\" } };\n\n// ループ元のデータ（順位変動など）を取得\n// ※ここなら確実にデータが見えます\nconst loopNodeData = $('Loop Pages').first().json;\n\nconst pageUrl = items[0].json.page;\nconst queryListText = items.map(item => {\n  const d = item.json;\n  return `・${d.query} (Rank: ${parseFloat(d.position).toFixed(1)}, Clicks: ${d.clicks}, Impr: ${d.impressions})`;\n}).slice(0, 20).join('\\n');\n\nreturn { \n  json: { \n    target_url: pageUrl, \n    query_summary: queryListText,\n    // ここでデータをバケツリレーに追加\n    clicks_diff: loopNodeData.clicks_diff,\n    pos_diff: loopNodeData.pos_diff\n  } \n};"
      },
      "typeVersion": 2
    },
    {
      "id": "85e489b2-567c-459c-9ef1-63f21900f8c4",
      "name": "Scrape Page",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1856,
        64
      ],
      "parameters": {
        "url": "={{ $json.target_url }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "18f2036f-37f0-44e3-a601-0e7f2ffffa10",
      "name": "Extract Content",
      "type": "n8n-nodes-base.html",
      "position": [
        2080,
        64
      ],
      "parameters": {
        "options": {},
        "operation": "extractHtmlContent",
        "extractionValues": {
          "values": [
            {
              "key": "page_title",
              "cssSelector": "title"
            },
            {
              "key": "h2_tags",
              "cssSelector": "h2",
              "returnArray": true
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f6775fd5-4696-4237-b4c8-f455fa378b28",
      "name": "AI Analyst",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        2304,
        64
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "content": "=You are an expert Web Editor skilled in SEO analysis.\nYou are analyzing a client's website traffic to improve rankings.\n\nThe following page has seen a DROP in rankings and clicks compared to last month. \nAnalyze the \"Search Queries\" and the actual \"Article Structure\" to understand the site's genre and target audience instantly.\nProvide the most effective improvement plan for that specific audience.\n\n## 🔹 Analysis Data\n- URL: {{ $('Format Queries').first().json.target_url }}\n- MoM Change: 📉 Clicks {{ Math.round($('Format Queries').first().json.clicks_diff) }} / Rank {{ Number($('Format Queries').first().json.pos_diff).toFixed(1) }} (Positive value means rank dropped)\n- Search Queries (User Needs):\n{{ $('Format Queries').first().json.query_summary }}\n\n## 🔹 Article Content (Current Reality)\n- Title: {{ $json.page_title }}\n- H2 Headings: {{ $json.h2_tags }}\n\n## 🔹 Writing Rules (Strict)\n1. **Do NOT use Markdown bolding (asterisks).** It makes Slack hard to read.\n2. Do NOT use cliché AI phrases like \"Ultimate Guide\" or \"Comprehensive Analysis\".\n3. Write in a human, engaging tone appropriate for the specific genre.\n\n## 🔹 Output Format\nUse the following emoji structure. No greetings.\n\n🚨 Alert: Ranking/Click Drop\n(Start by stating the quantitative drop: \"Clicks dropped by X, Rank dropped by Y\". Then, analyze the root cause of WHY Google/Users abandoned this page by comparing queries vs content. Be sharp. e.g., \"Title is too generic\", \"Answer is buried too deep\".)\n\n🧐Search Queries\n{{ $('Format Queries').item.json.query_summary }}\n\n✨ Title Improvement Ideas (3)\n1. [Specific idea with numbers/benefits]\n2. [Idea appealing to \"FOMO\" or curiosity]\n3. [Different angle from competitors]\n\n📝 Missing H2 Heading to Add\n(Propose ONE missing piece to satisfy the search intent. Explain why this heading is needed and what content it should cover.)"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "credential-id",
          "name": "openAiApi Credential"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "8c64cd04-e6d3-4d8f-b98d-29d78ca6851e",
      "name": "Format for Slack",
      "type": "n8n-nodes-base.code",
      "position": [
        2656,
        64
      ],
      "parameters": {
        "jsCode": "const aiJson = $input.item.json;\nlet aiText = \"AI Response Error\";\n\n// Normalize AI response location\nlet aiData = aiJson.output || aiJson.response || aiJson;\nif (typeof aiData === 'string') { try { aiData = JSON.parse(aiData); } catch(e) { aiText = aiData; } }\n\n// Extract text from structure\nif (Array.isArray(aiData) && aiData[0]?.content?.[0]?.text) aiText = aiData[0].content[0].text;\nelse if (aiData.content?.[0]?.text) aiText = aiData.content[0].text;\nelse if (aiData.text && typeof aiData.text === 'string') aiText = aiData.text;\nelse try { aiText = JSON.stringify(aiData); } catch(e) {}\n\n// Formatting\nlet cleanText = aiText.replace(/\\*\\*/g, '').replace(/\\\\n/g, '\\n');\nconst originalUrl = $('Format Queries').first().json.target_url || \"URL Unknown\";\n\n// Create Slack Header\nconst header = `📉 *SEO Improvement Report* \\n🔗 ${originalUrl}\\n\\n`;\n\nreturn { json: { slack_message: header + cleanText } };"
      },
      "typeVersion": 2
    },
    {
      "id": "5f2a2eb7-06c2-452e-884f-9d12c725fa37",
      "name": "Notify Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        2880,
        144
      ],
      "webhookId": "5a2d3c8c-3246-4657-a4b0-47b15594f88c",
      "parameters": {
        "text": "={{ $json.slack_message }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "example"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "id": "credential-id",
          "name": "slackOAuth2Api Credential"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "b33613a8-7291-411d-8f0e-3e24c8566deb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -64
      ],
      "parameters": {
        "width": 344,
        "height": 540,
        "content": "## 💡 About this workflow\nThis workflow automatically audits your website for SEO performance drops. It compares last month's data with the previous month using Google Search Console, identifies pages with declining traffic, and uses AI to prescribe specific content fixes.\n\n### How it works\n1. **Monitor:** Checks GSC for pages where clicks & rank have dropped.\n2. **Analyze:** Scrapes the live page content and compares it against actual search queries.\n3. **Report:** Sends a detailed Slack report with specific Title & H2 improvement ideas.\n\n### Setup steps\n1. **Config:** Add your GSC Property URL in the `📝 Edit Me: Config` node.\n2. **Credentials:** Connect your Google Search Console, OpenAI, and Slack accounts.\n3. **Schedule:** By default, it runs every Monday at 9:00 AM."
      },
      "typeVersion": 1
    },
    {
      "id": "1b3a24e8-deec-472d-8e82-86effc166c3e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        16,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 857,
        "height": 534,
        "content": "## 1. Data Collection\nFetch GSC data and filter for pages with negative performance."
      },
      "typeVersion": 1
    },
    {
      "id": "7a1a121d-145f-4578-8b4e-a9fd8a0ce4d4",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        896,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 1707,
        "height": 534,
        "content": "## 2. Deep Analysis\nFetch queries per URL, scrape the page content, and send to AI."
      },
      "typeVersion": 1
    },
    {
      "id": "de8d46e8-0352-44ab-b7c3-cc8594f65ea4",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2624,
        -64
      ],
      "parameters": {
        "color": 7,
        "width": 444,
        "height": 534,
        "content": "## 3. Report\nFormat the AI insight and alert Slack."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "85c04e0f-95b9-43ed-a80b-562eee2221a4",
  "connections": {
    "Wait 1s": {
      "main": [
        [
          {
            "node": "GSC: Get Queries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Analyst": {
      "main": [
        [
          {
            "node": "Format for Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Pages": {
      "main": [
        [],
        [
          {
            "node": "Wait 1s",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scrape Page": {
      "main": [
        [
          {
            "node": "Extract Content",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Slack": {
      "main": [
        [
          {
            "node": "Loop Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter: Drops": {
      "main": [
        [
          {
            "node": "Loop Pages",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Queries": {
      "main": [
        [
          {
            "node": "Scrape Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Content": {
      "main": [
        [
          {
            "node": "AI Analyst",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Schedule": {
      "main": [
        [
          {
            "node": "📝 Edit Me: Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format for Slack": {
      "main": [
        [
          {
            "node": "Notify Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GSC: Get Queries": {
      "main": [
        [
          {
            "node": "Format Queries",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GSC: Compare Period": {
      "main": [
        [
          {
            "node": "Filter: Drops",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "📝 Edit Me: Config": {
      "main": [
        [
          {
            "node": "GSC: Compare Period",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}