{
  "id": "k2TPXhp1ztskK70V",
  "name": "On-Page SEO + GEO Audit with IONOS AI Model Hub",
  "tags": [],
  "nodes": [
    {
      "id": "99cbeb4a-ba6f-435b-8059-1c6c5a9b9242",
      "name": "Form Trigger",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        2288,
        1008
      ],
      "parameters": {
        "options": {},
        "formTitle": "SEO + GEO Audit",
        "formFields": {
          "values": [
            {
              "fieldLabel": "URL",
              "placeholder": "https://example.com",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "Crawler",
              "fieldOptions": {
                "values": [
                  {
                    "option": "HTTP"
                  },
                  {
                    "option": "Headless Browser (Apify)"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "email",
              "fieldLabel": "Report email",
              "requiredField": true
            }
          ]
        },
        "formDescription": "Enter the URL to audit, choose your crawler, and receive the report by email."
      },
      "typeVersion": 2.2
    },
    {
      "id": "ee29cd4c-53a6-46f5-9e13-9eb2cb9722cd",
      "name": "Choose Crawler",
      "type": "n8n-nodes-base.switch",
      "position": [
        2544,
        1008
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json['Crawler'] }}",
                    "rightValue": "HTTP"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json['Crawler'] }}",
                    "rightValue": "Headless Browser (Apify)"
                  }
                ]
              }
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "a69feadc-5c30-4aa8-a37a-3df6f080faf5",
      "name": "Simple HTTP Crawl",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2800,
        880
      ],
      "parameters": {
        "url": "={{ $('Form Trigger').first().json['URL'] }}",
        "options": {
          "timeout": 30000,
          "redirect": {
            "redirect": {
              "maxRedirects": 5
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "User-Agent",
              "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
            },
            {
              "name": "Accept-Language",
              "value": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7"
            },
            {
              "name": "Accept",
              "value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
            },
            {
              "name": "Accept-Encoding",
              "value": "gzip, deflate, br"
            },
            {
              "name": "Cache-Control",
              "value": "no-cache"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "ad20c34b-1961-4950-bb07-1bb5500e46ef",
      "name": "Headless Browser Crawl",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2800,
        1152
      ],
      "parameters": {
        "url": "https://api.apify.com/v2/acts/apify~website-content-crawler/run-sync-get-dataset-items",
        "method": "POST",
        "options": {
          "timeout": 180000
        },
        "sendBody": true,
        "sendQuery": true,
        "bodyParameters": {
          "parameters": [
            {}
          ]
        },
        "queryParameters": {
          "parameters": [
            {
              "name": "token",
              "value": "YOUR_APIFY_API_TOKEN"
            },
            {
              "name": "timeout",
              "value": "120"
            },
            {
              "name": "memory",
              "value": "1024"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "107d4c77-5e16-4367-9b6f-ebb60f7e6120",
      "name": "Extract SEO Data",
      "type": "n8n-nodes-base.code",
      "position": [
        3104,
        1008
      ],
      "parameters": {
        "jsCode": "const item = $input.first().json;\nconst html = item.html || item.data || '';\nconst url = $('Form Trigger').first().json['URL'] || 'unknown';\n\nconst cleaned = html\n  .replace(/<!--[\\s\\S]*?-->/g, '')\n  .replace(/<script(?![\\s\\S]*?type=[\"']application\\/ld\\+json[\"'])[\\s\\S]*?<\\/script>/gi, '')\n  .replace(/<style[\\s\\S]*?<\\/style>/gi, '');\n\n// HEAD section (increased to 6000 chars to avoid truncating heavy schema)\nconst headMatch = cleaned.match(/<head[\\s\\S]*?<\\/head>/i);\nconst head = headMatch ? headMatch[0].substring(0, 6000) : '(no <head> found)';\n\n// Heading hierarchy\nconst headings = [];\nconst hMatches = cleaned.matchAll(/<h([1-6])[^>]*>([\\s\\S]*?)<\\/h[1-6]>/gi);\nfor (const m of hMatches) {\n  headings.push('H' + m[1] + ': ' + m[2].replace(/<[^>]+>/g, '').trim());\n}\n\n// Image alt attributes\nconst alts = [];\nconst imgMatches = cleaned.matchAll(/<img[^>]+>/gi);\nfor (const m of imgMatches) {\n  const alt = m[0].match(/alt=[\"']([^\"']*)[\"']/i);\n  alts.push(alt ? (alt[1] || '(empty alt)') : '(missing alt)');\n}\n\n// Internal and external links\nconst links = [];\nconst linkMatches = cleaned.matchAll(/<a[^>]+href=[\"']([^\"']+)[\"'][^>]*>([\\s\\S]*?)<\\/a>/gi);\nfor (const m of linkMatches) {\n  links.push({ href: m[1], text: m[2].replace(/<[^>]+>/g, '').trim().substring(0, 80) });\n}\n\n// Clean body text\nconst bodyText = cleaned\n  .replace(/<[^>]+>/g, ' ')\n  .replace(/\\s+/g, ' ')\n  .trim()\n  .substring(0, 8000);\n\nconst wordCount = bodyText.split(/\\s+/).filter(function(w) { return w.length > 1; }).length;\n\nreturn [{ json: {\n  url: url,\n  head: head,\n  text: bodyText,\n  wordCount: wordCount,\n  headings: headings.slice(0, 60).join('\\n'),\n  images: alts.slice(0, 40).join(' | '),\n  links: links.slice(0, 50)\n} }];"
      },
      "typeVersion": 2
    },
    {
      "id": "45c1718f-4a89-4de3-8dcf-cbeb2b98fa62",
      "name": "SEO + GEO Audit",
      "type": "@ionos-cloud/n8n-nodes-ionos-cloud.ionosCloudAiModelHub",
      "position": [
        3408,
        1008
      ],
      "parameters": {
        "model": "mistralai/Mistral-Nemo-Instruct-2407",
        "messages": {
          "messageValues": [
            {
              "content": "=You are a world-class SEO & GEO (Generative Engine Optimization) specialist with deep expertise in technical SEO, content strategy, and AI-search optimization.\n\nAnalyze the page data below and produce a single, complete audit report in Markdown.\n\n---\n\n## Page Data\n\n**URL:** {{ $json.url }}\n**Word count:** {{ $json.wordCount }} words\n\n### HEAD section (title, meta, canonical, schema, Open Graph\u2026)\n{{ $json.head }}\n\n### Heading hierarchy (H1\u2013H6)\n{{ $json.headings }}\n\n### Image alt attributes\n{{ $json.images }}\n\n### Links (href + anchor text)\n{{ $json.links }}\n\n### Page text content (cleaned)\n{{ $json.text }}\n\n---\n\n## Audit Instructions\n\nProduce a structured Markdown report in exactly TWO parts:\n\n### PART 1 \u2014 SEO AUDIT\nEvaluate every technical signal visible in the HTML:\n- Title tag: length (ideal 50\u201360 chars), primary keyword placement, uniqueness\n- Meta description: length (ideal 140\u2013160 chars), CTR potential, missing or duplicate\n- Canonical URL: present, self-referencing, correct protocol\n- Robots meta directive: indexability issues\n- Viewport meta: mobile-friendliness signal\n- Heading hierarchy: H1 count and uniqueness, H2/H3 logical structure\n- Structured data / Schema.org: types present, completeness, validation issues\n- Open Graph & Twitter Cards: completeness, image dimensions hint\n- Hreflang / international SEO: language targeting, missing alternates\n- Image alt attributes: missing, empty, or keyword-stuffed\n- Internal & external linking signals visible in the markup\n\n### PART 2 \u2014 GEO AUDIT (Generative Engine Optimization)\nAssess the page's readiness to be cited or featured by AI-powered search engines: Google AI Overviews, Bing Copilot, Perplexity, ChatGPT Search.\nEvaluate:\n- E-E-A-T signals (Experience, Expertise, Authoritativeness, Trustworthiness): author attribution, credentials, date signals\n- Factual clarity: direct, unambiguous statements that AI can extract and cite\n- Answer-ready content: FAQ blocks, definition sections, numbered steps, short direct answers\n- Structured data quality for AI parsers: HowTo, FAQPage, Article, Product, LocalBusiness schemas\n- Citation worthiness: original data, stats, quotes, unique insights\n- Brand entity clarity: consistent NAP, brand name mentions, same-as links\n- Content freshness signals: publication/modification dates in markup\n- Conversational intent matching: does the content answer the questions users ask AI assistants?\n\n---\n\nFor EACH part, organize findings under:\n- \ud83d\udd34 **Critical Issues** \u2014 Must fix immediately (high impact, blocks ranking or AI visibility)\n- \ud83d\udfe1 **Quick Wins** \u2014 Easy fixes with significant impact (can be done this week)\n- \ud83d\udfe2 **Opportunities** \u2014 Strategic improvements (require more effort but offer long-term gains)\n\nBe specific, actionable, and concise. Include concrete suggestions (e.g. rewrite examples, missing schema types). Start directly with PART 1 \u2014 no preamble or introduction."
            }
          ]
        },
        "resource": "openai",
        "requestOptions": {},
        "additionalFields": {}
      },
      "credentials": {
        "ionosCloudApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "363669cf-234e-4469-b77a-db02a14acb58",
      "name": "Markdown",
      "type": "n8n-nodes-base.markdown",
      "position": [
        3712,
        1008
      ],
      "parameters": {
        "mode": "markdownToHtml",
        "options": {},
        "markdown": "={{ $json.choices[0].message.content }}"
      },
      "typeVersion": 1
    },
    {
      "id": "4f18e8bd-83c4-44a5-af04-d64493e7419d",
      "name": "Gmail",
      "type": "n8n-nodes-base.gmail",
      "position": [
        3952,
        1008
      ],
      "parameters": {
        "sendTo": "={{ $('Form Trigger').first().json['Report email'] }}",
        "message": "={{ $json.data }}",
        "options": {},
        "subject": "=SEO + GEO Audit \u2014 {{ $('Form Trigger').first().json['URL'] }} \u2014 {{ new Date().toLocaleDateString('fr-FR') }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "99cba3a0-0795-4a57-89ce-65f0c2a6e882",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1744,
        496
      ],
      "parameters": {
        "width": 576,
        "height": 448,
        "content": "## Automated SEO + GEO Audit Workflow with AI Model Hub\n\n### How it works\n1. **Form** \u2014 Fill URL, crawler type, email\n2. **Switch** \u2014 Routes to HTTP or Headless crawler\n3. **Extract** \u2014 Parses HEAD, text, word count\n4. **AI Audit** \u2014 IONOS AI Model Hub (Mistral Nemo) analyzes SEO & GEO signals\n5. **HTML** \u2014 Converts Markdown report to email-ready format\n6. **Email** \u2014 Delivers audit to the address entered in the form\n\n### Setup\n- Add IONOS Cloud API credentials\n- For Headless path: add Apify API token in node (console.apify.com)\n- Enable workflow\n\n### Tips\n- **HTTP vs Headless** \u2014 Use HTTP for standard WordPress/static sites (faster, free). Switch to Headless only for React/Vue/Angular sites where content is JS-rendered.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e74e2d34-a8fb-4ae6-8f21-c16b218387b1",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2432,
        768
      ],
      "parameters": {
        "color": 7,
        "width": 288,
        "height": 176,
        "content": "## Crawler Choice\n\n**HTTP** \u2014 Fast, works for static & server-rendered sites\n\n**Headless Browser (Apify)** \u2014 Renders JavaScript via Playwright Chrome, needed for SPAs, React, Vue sites\n"
      },
      "typeVersion": 1
    },
    {
      "id": "fa80c764-375e-4689-b9e7-f4624047dc90",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3088,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 208,
        "content": "## AI Audit\n\n**AI Model Hub** analyzes:\n- Technical SEO (title, meta, schema, OG, hreflang)\n- GEO (E-E-A-T, answer-ready, citation-worthy content)"
      },
      "typeVersion": 1
    },
    {
      "id": "0d9d05d0-e0e9-41cc-8f0f-8d8508b4e3a7",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3744,
        736
      ],
      "parameters": {
        "color": 7,
        "width": 272,
        "height": 208,
        "content": "## Format & Send\n\n**Markdown \u2192 HTML** \u2014 Styled report\n\n**Gmail** \u2014 Delivers to address from the form"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "ce922429-1ede-4490-838c-6ccc847f07e0",
  "connections": {
    "Markdown": {
      "main": [
        [
          {
            "node": "Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Form Trigger": {
      "main": [
        [
          {
            "node": "Choose Crawler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Choose Crawler": {
      "main": [
        [
          {
            "node": "Simple HTTP Crawl",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Headless Browser Crawl",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SEO + GEO Audit": {
      "main": [
        [
          {
            "node": "Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract SEO Data": {
      "main": [
        [
          {
            "node": "SEO + GEO Audit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Simple HTTP Crawl": {
      "main": [
        [
          {
            "node": "Extract SEO Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Headless Browser Crawl": {
      "main": [
        [
          {
            "node": "Extract SEO Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}