{
  "name": "SEO Technical Audit",
  "nodes": [
    {
      "id": "9bb70532-f7ca-4ff9-b6cd-ba2b19834e0c",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2208,
        -288
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## SEO Technical Audit\n\n### How it works\n\nThis workflow runs a technical SEO audit for a configured website either manually or on a weekly schedule. It fetches page and post sitemaps, extracts URLs, then checks each URL for HTTP status, PageSpeed score, and Google Search Console indexing status. The results are merged into audit rows and appended to a Google Sheet for reporting.\n\n### Setup steps\n\n- Set the target website URL in the Config node, and confirm the site exposes the expected /page-sitemap.xml and /post-sitemap.xml files.\n- Configure credentials or API access for the PageSpeed Insights request, including any required Google API key or query parameters.\n- Configure Google Search Console API credentials with access to the target property for the indexing inspection request.\n- Connect Google Sheets credentials and select the destination spreadsheet and sheet in the Append Audit Row node.\n- Adjust and activate the Weekly Schedule trigger if the audit should run automatically.\n\n### Customization\n\nChange the sitemap paths, audit cadence, PageSpeed strategy or metrics, and the Google Sheets destination columns to match the site and reporting needs."
      },
      "typeVersion": 1
    },
    {
      "id": "1c3e6b61-6247-422f-a5f6-798cdec1d7e2",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1648,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 480,
        "content": "## Triggers and config\n\nStarts the audit manually or on a weekly schedule, then sets the website URL used by the rest of the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "ae58e1c0-4829-4166-86a6-66d55d7d0fe2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1248,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "content": "## Fetch page sitemap\n\nRequests the page sitemap XML and parses it into structured data for downstream URL extraction."
      },
      "typeVersion": 1
    },
    {
      "id": "597d4563-2250-4861-8fec-55441f20ba08",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1248,
        160
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Fetch post sitemap\n\nRequests the post sitemap XML and parses it into structured data alongside the page sitemap branch."
      },
      "typeVersion": 1
    },
    {
      "id": "01f61aa7-b7fb-4138-8bb3-c82a8d0455c6",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -768,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Combine URL list\n\nAppends the parsed sitemap outputs together and flattens them into a URL list for parallel audit checks."
      },
      "typeVersion": 1
    },
    {
      "id": "a28b146d-fc8d-4b34-910e-03259d88ac15",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "content": "## Check HTTP status\n\nRequests each discovered URL and extracts the URL and HTTP response status for the audit report."
      },
      "typeVersion": 1
    },
    {
      "id": "793fc721-6b8e-4668-b900-3aba73ed90f1",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        48
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "content": "## Check PageSpeed score\n\nCalls the PageSpeed Insights API for each URL and normalizes the resulting PageSpeed score."
      },
      "typeVersion": 1
    },
    {
      "id": "45d07f23-929c-427f-9daa-85aa39480adb",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 304,
        "content": "## Check indexing status\n\nUses the Search Console API to inspect each URL and sets whether it is indexed."
      },
      "typeVersion": 1
    },
    {
      "id": "1f67370f-fefa-4e6f-9764-7ac17185382d",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        -176
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 416,
        "content": "## Merge audit metrics\n\nCombines the HTTP status, PageSpeed, and indexing branches into a unified record per URL."
      },
      "typeVersion": 1
    },
    {
      "id": "cfeab93c-ed98-45a5-b695-477fd7fb372e",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        -80
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Save audit report\n\nBuilds the final report row with URL, HTTP status, PageSpeed score, and indexed state, then appends it to Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "4a24ba9f-42cc-4f84-b4eb-fd3643040df2",
      "name": "Manual Execution Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1600,
        0
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "528631d2-8653-4123-861a-e338f3cb7142",
      "name": "Set Website URL",
      "type": "n8n-nodes-base.set",
      "notes": "Set this to your website URL (no trailing slash) before running.",
      "position": [
        -1440,
        80
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "cfg1",
              "name": "websiteUrl",
              "type": "string",
              "value": "https://example.com"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "84cb4809-02d2-4ed3-b942-05d21023ae9e",
      "name": "Fetch Page Sitemap",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1200,
        -40
      ],
      "parameters": {
        "url": "={{ $json.websiteUrl }}/page-sitemap.xml",
        "options": {}
      },
      "typeVersion": 4.4
    },
    {
      "id": "e19aec03-d7a9-4ae5-a2c7-0d1f07175efc",
      "name": "Fetch Post Sitemap",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -1200,
        320
      ],
      "parameters": {
        "url": "={{ $json.websiteUrl }}/post-sitemap.xml",
        "options": {}
      },
      "typeVersion": 4.4
    },
    {
      "id": "6c556739-f674-41b7-8d57-8adc03eb8c97",
      "name": "Weekly Audit Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -1600,
        160
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 9
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "4461fac4-f565-4cdb-bfd0-47e6ab911fb9",
      "name": "Parse Page Sitemap XML",
      "type": "n8n-nodes-base.xml",
      "position": [
        -960,
        -40
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "941194d0-78f2-4fea-b49b-dae32dbd24d3",
      "name": "Merge Sitemaps",
      "type": "n8n-nodes-base.merge",
      "position": [
        -720,
        80
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "0ba0b235-d5da-4cd0-9953-302d13c30796",
      "name": "Parse Post Sitemap XML",
      "type": "n8n-nodes-base.xml",
      "position": [
        -960,
        320
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "f9d5d2a4-2d9d-466d-81de-16ebbba20c5f",
      "name": "Extract URLs from Sitemaps",
      "type": "n8n-nodes-base.code",
      "position": [
        -480,
        80
      ],
      "parameters": {
        "jsCode": "const urls = [];\nfor (const item of $input.all()) {\n  const urlset = item.json.urlset;\n  if (!urlset || !urlset.url) continue;\n  const list = Array.isArray(urlset.url) ? urlset.url : [urlset.url];\n  for (const u of list) {\n    const locVal = Array.isArray(u.loc) ? u.loc[0] : u.loc;\n    if (locVal) urls.push({ json: { url: locVal } });\n  }\n}\nreturn urls;"
      },
      "typeVersion": 2
    },
    {
      "id": "fedcdbd5-8ba9-4e7d-9d77-f303125a3f46",
      "name": "Fetch URL Status",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -200,
        -160
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "options": {
          "response": {
            "response": {
              "neverError": true,
              "fullResponse": true
            }
          }
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "aef06eba-7b86-45a7-b597-66eb9f369021",
      "name": "Set URL Status",
      "type": "n8n-nodes-base.set",
      "position": [
        40,
        -160
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "url",
              "type": "string",
              "value": "={{ $('Extract URLs from Sitemaps').item.json.url }}"
            },
            {
              "id": "a2",
              "name": "httpStatus",
              "type": "number",
              "value": "={{ $json.statusCode }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e6a81f9e-6802-4179-89bc-22d3c23eaec9",
      "name": "Combine Status and Speed",
      "type": "n8n-nodes-base.merge",
      "position": [
        280,
        -40
      ],
      "parameters": {
        "mode": "combine",
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "850592fb-0ee9-4e8b-b56a-2d2883de4aab",
      "name": "Fetch PageSpeed Score",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Requires a PageSpeed Insights API key (Generic Auth - Query Auth). Get one free from Google Cloud Console.",
      "position": [
        -192,
        176
      ],
      "parameters": {
        "url": "https://www.googleapis.com/pagespeedonline/v5/runPagespeed",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 4000
            }
          },
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "url",
              "value": "={{ $json.url }}"
            },
            {
              "name": "category",
              "value": "performance"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f35fd45c-ab68-4fed-b9d2-a3bbaf7a4bd4",
      "name": "Set PageSpeed Score",
      "type": "n8n-nodes-base.set",
      "position": [
        48,
        176
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "b1",
              "name": "url",
              "type": "string",
              "value": "={{ $('Extract URLs from Sitemaps').item.json.url }}"
            },
            {
              "id": "b2",
              "name": "pagespeedScore",
              "type": "number",
              "value": "={{ Math.round((($json.lighthouseResult && $json.lighthouseResult.categories && $json.lighthouseResult.categories.performance && $json.lighthouseResult.categories.performance.score) || 0) * 100) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "cc8d2c59-72e4-4f5a-9b3a-4657fa9ae1e0",
      "name": "Inspect URL Indexing",
      "type": "n8n-nodes-base.httpRequest",
      "notes": "Requires a Google API credential with Search Console access, and your site verified in Google Search Console.",
      "position": [
        -192,
        512
      ],
      "parameters": {
        "url": "https://searchconsole.googleapis.com/v1/urlInspection/index:inspect",
        "method": "POST",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 2000
            }
          },
          "response": {
            "response": {
              "neverError": true
            }
          }
        },
        "jsonBody": "={\n  \"inspectionUrl\": \"{{ $json.url }}\",\n  \"siteUrl\": \"{{ $('Set Website URL').first().json.websiteUrl }}/\"\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "googleApi"
      },
      "typeVersion": 4.4
    },
    {
      "id": "56633803-6525-4005-afe3-e1e0aa35d3c7",
      "name": "Set Indexing Status",
      "type": "n8n-nodes-base.set",
      "position": [
        48,
        512
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "c1",
              "name": "url",
              "type": "string",
              "value": "={{ $('Extract URLs from Sitemaps').item.json.url }}"
            },
            {
              "id": "c2",
              "name": "indexed",
              "type": "string",
              "value": "={{ ($json.inspectionResult && $json.inspectionResult.indexStatusResult && $json.inspectionResult.indexStatusResult.coverageState) || \"Unknown\" }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b791db16-3a9b-41fb-b353-9dd559e083bc",
      "name": "Consolidate All Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        520,
        80
      ],
      "parameters": {
        "mode": "combine",
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "66a21359-5972-4f82-b6e1-cb70b75fa427",
      "name": "Build Audit Row",
      "type": "n8n-nodes-base.set",
      "position": [
        760,
        80
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "d1",
              "name": "URL",
              "type": "string",
              "value": "={{ $('Extract URLs from Sitemaps').item.json.url }}"
            },
            {
              "id": "d2",
              "name": "HTTP Status",
              "type": "number",
              "value": "={{ $json.httpStatus }}"
            },
            {
              "id": "d3",
              "name": "PageSpeed Score",
              "type": "number",
              "value": "={{ $json.pagespeedScore }}"
            },
            {
              "id": "d4",
              "name": "Indexed",
              "type": "string",
              "value": "={{ $json.indexed }}"
            },
            {
              "id": "d5",
              "name": "Date Checked",
              "type": "string",
              "value": "={{ $now.toFormat(\"yyyy-LL-dd\") }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "0ac3a862-6dbc-4c99-8725-3355f8b394c0",
      "name": "Append to Audit Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "notes": "Create a Google Sheet with columns: URL, HTTP Status, PageSpeed Score, Indexed, Date Checked. Connect your own Google Sheets credential.",
      "position": [
        1000,
        80
      ],
      "parameters": {
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData"
        },
        "options": {},
        "resource": "sheet",
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Technical Audit"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Your Google Sheet (pick from list)"
        }
      },
      "typeVersion": 4.7
    }
  ],
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Merge Sitemaps": {
      "main": [
        [
          {
            "node": "Extract URLs from Sitemaps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set URL Status": {
      "main": [
        [
          {
            "node": "Combine Status and Speed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Audit Row": {
      "main": [
        [
          {
            "node": "Append to Audit Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Website URL": {
      "main": [
        [
          {
            "node": "Fetch Page Sitemap",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Post Sitemap",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch URL Status": {
      "main": [
        [
          {
            "node": "Set URL Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Page Sitemap": {
      "main": [
        [
          {
            "node": "Parse Page Sitemap XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Post Sitemap": {
      "main": [
        [
          {
            "node": "Parse Post Sitemap XML",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Indexing Status": {
      "main": [
        [
          {
            "node": "Consolidate All Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Set PageSpeed Score": {
      "main": [
        [
          {
            "node": "Combine Status and Speed",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Consolidate All Data": {
      "main": [
        [
          {
            "node": "Build Audit Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inspect URL Indexing": {
      "main": [
        [
          {
            "node": "Set Indexing Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch PageSpeed Score": {
      "main": [
        [
          {
            "node": "Set PageSpeed Score",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly Audit Schedule": {
      "main": [
        [
          {
            "node": "Set Website URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Page Sitemap XML": {
      "main": [
        [
          {
            "node": "Merge Sitemaps",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Post Sitemap XML": {
      "main": [
        [
          {
            "node": "Merge Sitemaps",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Combine Status and Speed": {
      "main": [
        [
          {
            "node": "Consolidate All Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Execution Trigger": {
      "main": [
        [
          {
            "node": "Set Website URL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract URLs from Sitemaps": {
      "main": [
        [
          {
            "node": "Fetch URL Status",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch PageSpeed Score",
            "type": "main",
            "index": 0
          },
          {
            "node": "Inspect URL Indexing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}