{
  "nodes": [
    {
      "id": "f24de7e0-34db-431d-9128-86f1c33e792a",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2160,
        -224
      ],
      "parameters": {
        "width": 508,
        "height": 1052,
        "content": "## SEO Knowledge Base Chatbot \u2014 Google Sheets + GPT-4o-mini\n\nFor SEO agencies, consultants, and marketing teams who want a branded AI chatbot that answers client or team questions using only your own approved content. Add Q&A pairs to a Google Sheet. The chatbot reads the full knowledge base on every question, answers strictly from those rows, and gives an honest fallback if the answer is not covered. Every exchange is logged to a second sheet tab for analytics and knowledge base improvement. Conversation memory keeps context across follow-up questions in the same session.\n\n## How it works\n- **1. Chat Trigger \u2014 Receive User Question** creates a public n8n Chat interface and receives each user message\n- **2. Set \u2014 Config Values** stores both Sheet IDs, tab names, company name, and bot persona\n- **3. Google Sheets \u2014 Read Knowledge Base** reads all rows from the SEO FAQ sheet\n- **4. Code \u2014 Build Knowledge Base Text** formats all Q&A rows into a structured text block and pulls the user message\n- **5. AI Agent \u2014 SEO Consultant** answers strictly from the knowledge base using GPT-4o-mini with conversation memory\n- **8. Set \u2014 Prepare Log Fields** assembles the Q&A exchange for logging and response\n- **9. Google Sheets \u2014 Log Chat** appends every exchange to the Chat Log tab\n- **10. Set \u2014 Return Answer to Chat** sends the bot reply back to the chat interface\n\n## Set up steps\n1. In **2. Set \u2014 Config Values** \u2014 replace knowledgeBaseSheetId, knowledgeBaseSheetName, logSheetId, logSheetName, companyName, and botPersona with your values\n2. In **3. Google Sheets \u2014 Read Knowledge Base** \u2014 connect your Google Sheets OAuth2 credential\n3. In **6. OpenAI \u2014 GPT-4o-mini Model** \u2014 connect your OpenAI credential\n4. In **9. Google Sheets \u2014 Log Chat** \u2014 connect your Google Sheets OAuth2 credential\n5. Create your knowledge base sheet with tab SEO FAQ and columns: Question, Answer, Category, Last Updated\n6. Create a Chat Log tab with columns: Session ID, Timestamp, User Question, Bot Answer\n7. Activate the workflow and copy the Chat URL from node 1"
      },
      "typeVersion": 1
    },
    {
      "id": "7af37a53-acca-430b-bec0-d513c2494fc9",
      "name": "Section \u2014 Chat Input and Config",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1600,
        16
      ],
      "parameters": {
        "color": 5,
        "width": 596,
        "height": 388,
        "content": "## Chat Input and Config\nThe Chat Trigger creates a public chat interface. Config stores both Sheet IDs, tab names, company name, bot persona, and a session ID generated per conversation."
      },
      "typeVersion": 1
    },
    {
      "id": "b304c765-2415-438e-8ce2-6159fcaec764",
      "name": "Section \u2014 Knowledge Base Loading",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -976,
        16
      ],
      "parameters": {
        "color": 6,
        "width": 468,
        "height": 388,
        "content": "## Knowledge Base Loading\nReads all Q&A rows from the Google Sheets SEO FAQ tab. Formats them into a numbered Q&A text block. Also pulls the user message from the Chat Trigger for passing to the AI."
      },
      "typeVersion": 1
    },
    {
      "id": "730658bc-c296-4838-8db7-2694b346a53c",
      "name": "Section \u2014 AI Answer Generation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -400,
        -32
      ],
      "parameters": {
        "color": 6,
        "width": 384,
        "height": 756,
        "content": "## AI Answer Generation\nGPT-4o-mini answers strictly from the injected knowledge base. If the question is not covered, it returns an honest fallback message. Conversation memory keeps context for follow-up questions in the same session."
      },
      "typeVersion": 1
    },
    {
      "id": "824b09b2-fc33-4f3e-b248-b8fb52a103c9",
      "name": "Section \u2014 Logging and Chat Response",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        96,
        -96
      ],
      "parameters": {
        "color": 4,
        "width": 516,
        "height": 676,
        "content": "## Logging and Chat Response\nEvery Q&A exchange is logged to the Chat Log sheet for analytics and KB improvement. The bot answer is also returned to the chat interface simultaneously."
      },
      "typeVersion": 1
    },
    {
      "id": "cc0af5e9-009b-44bc-96f9-7a6102394bf8",
      "name": "2. Set \u2014 Config Values",
      "type": "n8n-nodes-base.set",
      "position": [
        -1168,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-001",
              "name": "knowledgeBaseSheetId",
              "type": "string",
              "value": "YOUR_KNOWLEDGE_BASE_SHEET_ID"
            },
            {
              "id": "cfg-002",
              "name": "knowledgeBaseSheetName",
              "type": "string",
              "value": "SEO FAQ"
            },
            {
              "id": "cfg-003",
              "name": "logSheetId",
              "type": "string",
              "value": "YOUR_CHAT_LOG_SHEET_ID"
            },
            {
              "id": "cfg-004",
              "name": "logSheetName",
              "type": "string",
              "value": "Chat Log"
            },
            {
              "id": "cfg-005",
              "name": "companyName",
              "type": "string",
              "value": "YOUR COMPANY NAME"
            },
            {
              "id": "cfg-006",
              "name": "botPersona",
              "type": "string",
              "value": "You are a professional SEO consultant at YOUR COMPANY NAME. You only answer questions about SEO, digital marketing, and website optimization."
            },
            {
              "id": "cfg-007",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $now.toMillis().toString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "7aff16e6-e2b7-4561-84ba-a8b953582945",
      "name": "3. Google Sheets \u2014 Read Knowledge Base",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -912,
        192
      ],
      "parameters": {
        "operation": "readOrSearch",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.knowledgeBaseSheetId }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "4019ab32-c7a8-480b-b5b5-502f1637a7ff",
      "name": "4. Code \u2014 Build Knowledge Base Text",
      "type": "n8n-nodes-base.code",
      "position": [
        -672,
        192
      ],
      "parameters": {
        "jsCode": "// Combine all knowledge base rows into a single readable text block\nconst kbRows = $input.all();\nconst config = $('2. Set \u2014 Config Values').item.json;\nconst userMessage = $('1. Chat Message Received').item.json.chatInput || '';\n\nif (!kbRows || kbRows.length === 0) {\n  return [{\n    json: {\n      knowledgeBase: 'Knowledge base is empty. Please add Q&A rows to the SEO FAQ sheet.',\n      userMessage,\n      sessionId: config.sessionId,\n      botPersona: config.botPersona,\n      companyName: config.companyName,\n      logSheetId: config.logSheetId,\n      logSheetName: config.logSheetName,\n      timestamp: new Date().toISOString().replace('T', ' ').substring(0, 16)\n    }\n  }];\n}\n\n// Build knowledge base text from all rows\nlet kbText = '';\nkbRows.forEach((row, index) => {\n  const q = row.json['Question'] || row.json['question'] || '';\n  const a = row.json['Answer'] || row.json['answer'] || '';\n  const cat = row.json['Category'] || row.json['category'] || 'General';\n  if (q && a) {\n    kbText += `Q${index + 1} [${cat}]: ${q}\\nA${index + 1}: ${a}\\n\\n`;\n  }\n});\n\nreturn [{\n  json: {\n    knowledgeBase: kbText || 'No valid Q&A pairs found in knowledge base.',\n    userMessage,\n    sessionId: config.sessionId,\n    botPersona: config.botPersona,\n    companyName: config.companyName,\n    logSheetId: config.logSheetId,\n    logSheetName: config.logSheetName,\n    timestamp: new Date().toISOString().replace('T', ' ').substring(0, 16)\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "2ac7f02c-ca9a-4536-aa5f-7e2ee62bbd6d",
      "name": "5. AI Agent \u2014 SEO Consultant",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -320,
        192
      ],
      "parameters": {
        "text": "={{ $json.botPersona }}\n\nYou have access to the following SEO knowledge base. Use ONLY this knowledge base to answer questions. Do not make up answers. Do not use outside knowledge.\n\nKNOWLEDGE BASE:\n{{ $json.knowledgeBase }}\n\nCURRENT QUESTION FROM USER:\n{{ $json.userMessage }}\n\nINSTRUCTIONS:\n1. Search the knowledge base carefully for the answer to this question.\n2. If you find a relevant answer, respond clearly and helpfully. You can rephrase and expand the answer in your own words.\n3. If the question is not covered in the knowledge base, say exactly: I do not have information about this topic in my current knowledge base. Please contact {{ $json.companyName }} support directly for help with this.\n4. Keep answers concise \u2014 under 150 words.\n5. Plain text only. No markdown. No bullet symbols. No asterisks.\n6. Be friendly and professional.",
        "options": {},
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "6a34786c-4f41-4610-9fff-56ffacb0cbfc",
      "name": "6. OpenAI \u2014 GPT-4o-mini Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        -320,
        400
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {
          "maxTokens": 400,
          "temperature": 0.3
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "063d7045-435b-4e9c-af65-276a988b04f3",
      "name": "7. Memory \u2014 Conversation Buffer",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -224,
        544
      ],
      "parameters": {},
      "typeVersion": 1.3
    },
    {
      "id": "b0be553e-6db2-455c-883c-c9ebdac3a3ef",
      "name": "8. Set \u2014 Prepare Log Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        144,
        192
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "log-001",
              "name": "botAnswer",
              "type": "string",
              "value": "={{ $json.output || 'No response generated.' }}"
            },
            {
              "id": "log-002",
              "name": "userQuestion",
              "type": "string",
              "value": "={{ $('4. Code \u2014 Build Knowledge Base Text').item.json.userMessage }}"
            },
            {
              "id": "log-003",
              "name": "sessionId",
              "type": "string",
              "value": "={{ $('4. Code \u2014 Build Knowledge Base Text').item.json.sessionId }}"
            },
            {
              "id": "log-004",
              "name": "timestamp",
              "type": "string",
              "value": "={{ $('4. Code \u2014 Build Knowledge Base Text').item.json.timestamp }}"
            },
            {
              "id": "log-005",
              "name": "logSheetId",
              "type": "string",
              "value": "={{ $('4. Code \u2014 Build Knowledge Base Text').item.json.logSheetId }}"
            },
            {
              "id": "log-006",
              "name": "logSheetName",
              "type": "string",
              "value": "={{ $('4. Code \u2014 Build Knowledge Base Text').item.json.logSheetName }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "85d58dcb-4f3c-45dc-9f8e-bca4cc334dc9",
      "name": "9. Google Sheets \u2014 Log Chat",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        368,
        32
      ],
      "parameters": {
        "columns": {
          "value": {
            "Timestamp": "={{ $json.timestamp }}",
            "Bot Answer": "={{ $json.botAnswer }}",
            "Session ID": "={{ $json.sessionId }}",
            "User Question": "={{ $json.userQuestion }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.logSheetName }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.logSheetId }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "84a83ea2-6893-4cd6-b4d8-816d360bd8b2",
      "name": "10. Set \u2014 Return Answer to Chat",
      "type": "n8n-nodes-base.set",
      "position": [
        368,
        352
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "resp-001",
              "name": "response",
              "type": "string",
              "value": "={{ $('8. Set \u2014 Prepare Log Fields').item.json.botAnswer }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "8d51d7d3-b35f-468d-a5f7-0c218c822b82",
      "name": "1. Chat Message Received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "notes": "CHAT TRIGGER \u2014 No credentials needed.\n\nThis creates an n8n Chat interface at a public URL.\n\nHOW TO GET THE CHAT URL:\n1. Activate the workflow\n2. Click on this node\n3. Copy the Chat URL shown\n4. Share this URL with your team or embed it\n\nCustomize the chat UI in parameters:\n- title \u2192 Chat window heading\n- subtitle \u2192 Description shown under title\n- inputPlaceholder \u2192 Hint text in the input box\n\nThe chat supports multi-turn conversation\n(user can ask follow-up questions naturally)",
      "position": [
        -1520,
        192
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    }
  ],
  "connections": {
    "1. Chat Message Received": {
      "main": [
        [
          {
            "node": "2. Set \u2014 Config Values",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2. Set \u2014 Config Values": {
      "main": [
        [
          {
            "node": "3. Google Sheets \u2014 Read Knowledge Base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "8. Set \u2014 Prepare Log Fields": {
      "main": [
        [
          {
            "node": "9. Google Sheets \u2014 Log Chat",
            "type": "main",
            "index": 0
          },
          {
            "node": "10. Set \u2014 Return Answer to Chat",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "5. AI Agent \u2014 SEO Consultant": {
      "main": [
        [
          {
            "node": "8. Set \u2014 Prepare Log Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "6. OpenAI \u2014 GPT-4o-mini Model": {
      "ai_languageModel": [
        [
          {
            "node": "5. AI Agent \u2014 SEO Consultant",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "7. Memory \u2014 Conversation Buffer": {
      "ai_memory": [
        [
          {
            "node": "5. AI Agent \u2014 SEO Consultant",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "4. Code \u2014 Build Knowledge Base Text": {
      "main": [
        [
          {
            "node": "5. AI Agent \u2014 SEO Consultant",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "3. Google Sheets \u2014 Read Knowledge Base": {
      "main": [
        [
          {
            "node": "4. Code \u2014 Build Knowledge Base Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}