完全なSEO監査ワークフロー、HTML要約を自動化
中級
これはMarket Research分野の自動化ワークフローで、7個のノードを含みます。主にSet, Code, Html, Gmail, HttpRequestなどのノードを使用。 毎日のSEO監査ワークフローでHTMLレポートをGmail/Slackに送信
前提条件
- •Googleアカウント + Gmail API認証情報
- •ターゲットAPIの認証情報が必要な場合あり
カテゴリー
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
"id": "ak2jPqnpYMKMo8Bp",
"meta": {
"instanceId": "e0fd1578cd5453d4707742d6846391bbf1c4d865d540d8236161c7a6376cbd50",
"templateCredsSetupCompleted": true
},
"name": "Complete SEO Audit Workflow with Automated HTML Summaries",
"tags": [],
"nodes": [
{
"id": "2fa7bca3-02c4-4ded-b4ea-b8dca5314257",
"name": "付箋",
"type": "n8n-nodes-base.stickyNote",
"position": [
144,
-560
],
"parameters": {
"width": 796,
"height": 644,
"content": "## Complete SEO Audit Workflow with Automated HTML Reports via Gmail or Slack\n\n### Purpose \nRun daily, in-depth audits of specified pages, checking everything from meta tags and heading structure to Core Web Vitals, accessibility, structured data, and security headers—so you catch issues before they impact your rankings.\n\n### Benefits \n- **Proactive Monitoring:** Identify on-page and technical SEO errors as they arise. \n- **Time Savings:** Automate repetitive checks and free your team to focus on strategy. \n- **Actionable Insights:** “Top 3 Priorities” and categorized issues speed up remediation.\n\n### Output \n• A formatted HTML report delivered via Gmail (or Slack) \n• Clear, actionable “Top 3 Priorities,” categorized On-Page vs. Technical issues, and next-steps links\n\n### Requirements & Customization \n- **Gmail/Slack Credentials:** For report delivery. \n- **Easy Customization:** \n - Edit URLs & recipients in the “Set Variables” node. \n - Tweak audit frequency in the Schedule Trigger. \n - Enhance the Code node with extra checks or third-party integrations. \n"
},
"typeVersion": 1
},
{
"id": "b64d81da-cc22-4fdd-9146-b76a29721047",
"name": "日次監査トリガー",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
128,
144
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "b12cf011-73cc-4890-bf15-1292201d3f60",
"name": "ターゲットと受信者の設定",
"type": "n8n-nodes-base.set",
"position": [
320,
144
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "44337ce3-4e65-4d7b-9b1a-cf77f8412169",
"name": "siteUrl",
"type": "string",
"value": "https://example.com/"
},
{
"id": "60e53201-5d1b-4665-9f13-aad194cd653c",
"name": "emailFrom",
"type": "string",
"value": "exampleFrom@example.com"
},
{
"id": "dc19de25-3f64-4244-9a3e-65d5178181c5",
"name": "emailTo",
"type": "string",
"value": "exampleTo@example.com"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "d84cbda7-a9e0-4c40-86da-e8914cf99e8f",
"name": "HTTP Fetch Page Content",
"type": "n8n-nodes-base.httpRequest",
"position": [
528,
144
],
"parameters": {
"url": "={{$node[\"Configure Target & Recipients\"].json.siteUrl}}\n",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "f25b7ba0-54e9-4e5e-85f8-936f9ffd3930",
"name": "オンページ要素の解析",
"type": "n8n-nodes-base.html",
"position": [
736,
144
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"dataPropertyName": "=data",
"extractionValues": {
"values": [
{
"key": "title",
"cssSelector": "title"
},
{
"key": "metaDesc",
"attribute": "content",
"cssSelector": "meta[name=\"description\"]",
"returnValue": "attribute"
},
{
"key": "h1Tags",
"cssSelector": "h1",
"returnArray": true
},
{
"key": "h2Tags",
"cssSelector": "h2",
"returnArray": true
},
{
"key": "imgAlts",
"attribute": "alt",
"cssSelector": "img",
"returnArray": true,
"returnValue": "attribute"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "f097edcb-fb09-4eb7-96dc-398f8e3dbecd",
"name": "SEO監査ロジックの実行",
"type": "n8n-nodes-base.code",
"position": [
944,
144
],
"parameters": {
"jsCode": "// Collect results for each URL\nconst output = [];\n\nfor (const item of items) {\n const d = item.json;\n const issues = [];\n const suggestions = {};\n\n function addIssue(code, message, suggestion) {\n issues.push({ code, message });\n suggestions[code] = suggestion;\n }\n\n // 1. Title length\n if (!d.title) {\n addIssue('missing_title', 'Missing <title>', 'Add a descriptive <title> (30–60 chars).');\n } else if (d.title.length < 30) {\n addIssue('short_title', `Title too short (${d.title.length} chars)`, 'Increase title length to ≥30 chars.');\n } else if (d.title.length > 60) {\n addIssue('long_title', `Title too long (${d.title.length} chars)`, 'Reduce title to ≤60 chars.');\n }\n\n // 2. Meta description\n if (!d.metaDesc) {\n addIssue('missing_meta_desc', 'Missing meta description', 'Add <meta name=\"description\"> (50–160 chars).');\n } else if (d.metaDesc.length < 50) {\n addIssue('short_meta_desc', `Meta description too short (${d.metaDesc.length} chars)`, 'Increase description to ≥50 chars.');\n } else if (d.metaDesc.length > 160) {\n addIssue('long_meta_desc', `Meta description too long (${d.metaDesc.length} chars)`, 'Shorten description to ≤160 chars.');\n }\n\n // 3. Robots, viewport, canonical, lang\n if (!d.metaRobots) {\n addIssue('missing_robots', 'Missing meta robots tag', 'Add <meta name=\"robots\" content=\"index,follow\">.');\n }\n if (!d.metaViewport || !d.metaViewport.includes('width=device-width')) {\n addIssue('viewport', 'Missing/incorrect viewport tag', 'Add <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">.');\n }\n if (!d.linkCanonical) {\n addIssue('canonical', 'Missing canonical', 'Add <link rel=\"canonical\" href=\"YOUR_URL\">.');\n }\n if (!d.htmlLang) {\n addIssue('lang', 'Missing lang attribute', 'Add <html lang=\"en\">.');\n }\n\n // 4. Word count\n if (typeof d.wordCount === 'number' && d.wordCount < 300) {\n addIssue('low_word_count', `Low word count (${d.wordCount} words)`, 'Aim for ≥300 words.');\n }\n\n // 5. Headings\n const h1 = (d.h1Tags || []).length;\n const h2 = (d.h2Tags || []).length;\n const h3 = (d.h3Tags || []).length;\n if (h1 !== 1) {\n addIssue('h1', `${h1} <h1> tags`, 'Use exactly one <h1>.');\n }\n if (h2 === 0) {\n addIssue('h2', 'No <h2> tags', 'Add ≥1 <h2> for sections.');\n }\n if (h3 === 0) {\n addIssue('h3', 'No <h3> tags', 'Use <h3> for subsections.');\n }\n\n // 6. Images alt text\n if (Array.isArray(d.imgAlts)) {\n const missing = d.imgAlts.filter(a => !a || !a.trim()).length;\n if (missing) {\n addIssue('img_alt', `${missing} images missing alt`, 'Provide descriptive alt text.');\n }\n }\n\n // 7. Broken links\n if (Array.isArray(d.links)) {\n const broken = d.links.filter(l => l.status >= 400).length;\n if (broken) {\n addIssue('broken_links', `${broken} broken links`, 'Fix or remove broken URLs.');\n }\n }\n\n // 8. Structured data\n if (!d.structuredData || d.structuredData.length === 0) {\n addIssue('schema', 'No structured data', 'Implement JSON-LD schema markup.');\n }\n\n // 9. Core Web Vitals\n if (d.metrics) {\n const { LCP, INP, CLS } = d.metrics;\n if (LCP > 2500) {\n addIssue('lcp', `LCP too slow (${LCP} ms)`, 'Optimize images and server response.');\n }\n if (INP > 200) {\n addIssue('inp', `INP high (${INP} ms)`, 'Minimize JavaScript execution.');\n }\n if (CLS > 0.1) {\n addIssue('cls', `CLS unstable (${CLS})`, 'Set image dimensions and pre-load fonts.');\n }\n }\n\n // Summary\n const pass = issues.length === 0;\n const summary = pass ? 'All checks passed! 🎉' : `${issues.length} issue${issues.length > 1 ? 's' : ''} detected`;\n\n // Markdown report\n let markdown = `## SEO Audit for ${d.siteUrl || d.url}\\n`;\n markdown += `**Status:** ${pass ? 'PASS ✅' : 'FAIL ❌'}\\n`;\n markdown += `**Summary:** ${summary}\\n`;\n if (!pass) {\n markdown += `\\n### Issues & Suggestions\\n`;\n issues.forEach(({ code, message }) => {\n markdown += `- **${message}** \\n _Suggestion:_ ${suggestions[code]}\\n`;\n });\n }\n\n output.push({\n json: {\n siteUrl: d.siteUrl || d.url,\n pass,\n summary,\n issues,\n suggestions,\n markdownReport: markdown,\n },\n });\n}\n\nreturn output;\n"
},
"typeVersion": 2
},
{
"id": "81cd1593-0669-4f68-bc12-cac12e30f327",
"name": "監査レポートのメール送信",
"type": "n8n-nodes-base.gmail",
"position": [
1168,
144
],
"webhookId": "5394c49f-09fb-4f0f-ba2f-0f312d197b53",
"parameters": {
"sendTo": "={{$node[\"Configure Target & Recipients\"].json.emailTo}}\n\n",
"message": "=<!DOCTYPE html>\n<html>\n<head>\n <meta charset=\"UTF-8\" />\n <style>\n body { font-family: Arial, sans-serif; color: #333; line-height: 1.4; padding: 20px; }\n .header { display: flex; align-items: center; margin-bottom: 20px; }\n .logo { height: 40px; margin-right: 15px; }\n .title { font-size: 24px; color: #2a6ebb; margin: 0; }\n .meta { margin: 5px 0 20px; }\n .status-pass { color: green; font-weight: bold; }\n .status-fail { color: red; font-weight: bold; }\n .summary-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }\n .summary-table td { padding: 8px; border: 1px solid #eee; }\n .issues-container { display: flex; gap: 20px; }\n .column { flex: 1; }\n .column h4 { border-bottom: 1px solid #ddd; padding-bottom: 5px; }\n .issues-list { list-style: none; padding: 0; margin: 0; }\n .issues-list li { margin: 8px 0; }\n .suggestion { display: block; margin-left: 15px; font-style: italic; color: #555; }\n .priorities { background: #f9f9f9; padding: 15px; border-left: 4px solid #2a6ebb; margin-bottom: 20px; }\n .next-steps { margin-top: 30px; font-size: 14px; }\n .next-steps a { color: #2a6ebb; text-decoration: none; }\n code { background: #eef; padding: 2px 4px; border-radius: 3px; }\n </style>\n</head>\n<body>\n\n <div class=\"header\">\n <div>\n <h1 class=\"title\">SEO Audit Report</h1>\n <div class=\"meta\">Date: {{ new Date().toLocaleDateString() }}</div>\n </div>\n </div>\n\n <p>\n <strong>Page:</strong> {{ $node[\"Run SEO Audit Logic\"].json.siteUrl }}<br/>\n <strong>Status:</strong>\n <span class=\"{{ $node[\"Run SEO Audit Logic\"].json.pass ? 'status-pass' : 'status-fail' }}\">\n {{ $node[\"Run SEO Audit Logic\"].json.pass ? 'PASS ✅' : 'FAIL ❌' }}\n </span>\n </p>\n\n <div class=\"priorities\">\n <strong>🚩 Top 3 Priorities:</strong>\n <ol>\n {{\n $node[\"Run SEO Audit Logic\"].json.issues\n .slice(0, 3)\n .map(i => `<li>${i.message.replace(/</g,'<').replace(/>/g,'>')}</li>`)\n .join('')\n }}\n </ol>\n </div>\n\n <table class=\"summary-table\">\n <tr>\n <td><strong>Total Issues</strong></td>\n <td>{{ $node[\"Run SEO Audit Logic\"].json.issues.length }}</td>\n </tr>\n <tr>\n <td><strong>Broken Links</strong></td>\n <td>\n {{\n $node[\"Run SEO Audit Logic\"].json.issues.filter(i => i.code === 'broken_links').length\n }}\n </td>\n </tr>\n <tr>\n <td><strong>CWV Alerts</strong></td>\n <td>\n {{\n $node[\"Run SEO Audit Logic\"].json.issues\n .filter(i => ['lcp','inp','cls'].includes(i.code))\n .length\n }}\n </td>\n </tr>\n </table>\n\n <div class=\"issues-container\">\n <!-- On‑Page Issues -->\n <div class=\"column\">\n <h4>📝 On‑Page Issues</h4>\n <ul class=\"issues-list\">\n {{\n $node[\"Run SEO Audit Logic\"].json.issues\n .filter(i => [\n 'missing_title','short_title','long_title',\n 'missing_meta_desc','short_meta_desc','long_meta_desc',\n 'h1','h2','h3','img_alt','schema'\n ].includes(i.code))\n .map(i => {\n const msg = i.message.replace(/</g,'<').replace(/>/g,'>');\n const sug = $node[\"Run SEO Audit Logic\"].json.suggestions[i.code]\n .replace(/</g,'<').replace(/>/g,'>');\n return `\n <li>\n ⚠️ <strong>${msg}</strong>\n <span class=\"suggestion\">\n Suggestion: <code>${sug}</code>\n </span>\n </li>`;\n })\n .join('')\n }}\n </ul>\n </div>\n\n <!-- Technical Issues -->\n <div class=\"column\">\n <h4>🔧 Technical Issues</h4>\n <ul class=\"issues-list\">\n {{\n $node[\"Run SEO Audit Logic\"].json.issues\n .filter(i => ![\n 'missing_title','short_title','long_title',\n 'missing_meta_desc','short_meta_desc','long_meta_desc',\n 'h1','h2','h3','img_alt','schema'\n ].includes(i.code))\n .map(i => {\n const msg = i.message.replace(/</g,'<').replace(/>/g,'>');\n const sug = $node[\"Run SEO Audit Logic\"].json.suggestions[i.code]\n .replace(/</g,'<').replace(/>/g,'>');\n return `\n <li>\n ⚙️ <strong>${msg}</strong>\n <span class=\"suggestion\">\n Suggestion: <code>${sug}</code>\n </span>\n </li>`;\n })\n .join('')\n }}\n </ul>\n </div>\n </div>\n\n <div class=\"next-steps\">\n <p><strong>Next Steps:</strong></p>\n <ol>\n <li>Review the above suggestions and assign tickets in your tracker.</li>\n <li>Re‑run this audit after fixes are deployed to confirm all PASS.</li>\n </ol>\n </div>\n\n</body>\n</html>\n",
"options": {},
"subject": "={{$node[\"Configure Target & Recipients\"].json.siteUrl}}"
},
"credentials": {
"gmailOAuth2": {
"id": "jkKHvU2Pb9X5WJk5",
"name": "Gmail account"
}
},
"typeVersion": 2.1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "bc8a99b9-d397-4881-a02e-6aab78b364dc",
"connections": {
"b64d81da-cc22-4fdd-9146-b76a29721047": {
"main": [
[
{
"node": "b12cf011-73cc-4890-bf15-1292201d3f60",
"type": "main",
"index": 0
}
]
]
},
"f097edcb-fb09-4eb7-96dc-398f8e3dbecd": {
"main": [
[
{
"node": "81cd1593-0669-4f68-bc12-cac12e30f327",
"type": "main",
"index": 0
}
]
]
},
"d84cbda7-a9e0-4c40-86da-e8914cf99e8f": {
"main": [
[
{
"node": "f25b7ba0-54e9-4e5e-85f8-936f9ffd3930",
"type": "main",
"index": 0
}
]
]
},
"f25b7ba0-54e9-4e5e-85f8-936f9ffd3930": {
"main": [
[
{
"node": "f097edcb-fb09-4eb7-96dc-398f8e3dbecd",
"type": "main",
"index": 0
}
]
]
},
"b12cf011-73cc-4890-bf15-1292201d3f60": {
"main": [
[
{
"node": "d84cbda7-a9e0-4c40-86da-e8914cf99e8f",
"type": "main",
"index": 0
}
]
]
}
}
}よくある質問
このワークフローの使い方は?
上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。
このワークフローはどんな場面に適していますか?
中級 - 市場調査
有料ですか?
このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。
関連ワークフロー
競合他社コンテンツギャップ分析ツール:構題マッピングの自動化
Gemini AI、Apify、Google Sheetsを使用して競合企業のコンテンツギャップを分析
If
Set
Code
+
If
Set
Code
30 ノードMychel Garzon
その他
コミュニティ問題モニタ(OpenRouter AI、Reddit、フォーラムクロール)
OpenRouter AI、Reddit、フォーラムクロールでコミュニティの問題を監視
Set
Code
Html
+
Set
Code
Html
29 ノードJulian Kaiser
市場調査
GA4異常検知とSlack、メールによる自動 alerting
GA4異常検知と自動Slack及びメールアラート
If
Set
Code
+
If
Set
Code
9 ノードArtur
市場調査
AI履歴書最適化ツール
Gemini分析とメールレポートで履歴書を職位記述に一致させる
Set
Code
Gmail
+
Set
Code
Gmail
18 ノードMychel Garzon
AI要約
Gmailへn8nによる送信タイムリミットの通知
AIベースのn8nリリースノート要約通知(Gmail経由でGPT-5-Miniを使用)
Set
Code
Html
+
Set
Code
Html
16 ノードJeff Huera
個人の生産性
私のワークフロー
LinkedIn、Google Sheets、AI を使って 求人検索とAIを活用した自動採用情報検索、AI提供の求人検索とCVスコアリングの自動化を提供
Set
Code
Html
+
Set
Code
Html
27 ノードJugal