AutomationFlowsAI & RAG › Build a Website AI Chatbot with Lead Capture Using Gemini and Supabase RAG

Build a Website AI Chatbot with Lead Capture Using Gemini and Supabase RAG

ByShadrack @shadrack on n8n.io

This workflow deploys a fully customizable AI chatbot that can be embedded on any website, from custom-coded sites to platforms like WordPress. The chatbot is powered by n8n, uses Supabase for memory and RAG, and integrates SerpAPI, Google Calendar, SMTP, and Google Sheets to…

Event trigger★★★★☆ complexityAI-powered24 nodesGoogle Gemini ChatGoogle Drive TriggerGoogle DriveSupabase Vector StoreDocument Default Data LoaderText Splitter Recursive Character Text SplitterOpenAI EmbeddingsTool Think
AI & RAG Trigger: Event Nodes: 24 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #10365 — we link there as the canonical source.

This workflow follows the Agent → Chat Trigger recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "a32dc9ce-afcd-4929-9bcf-70aae499bc3d",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        -1696,
        464
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "fbe51365-14a2-48fc-9e5a-83eaede8db9a",
      "name": "Google Drive Trigger",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        -2400,
        1024
      ],
      "parameters": {
        "event": "fileCreated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "1-IwC1Zsn5MB0-EjsRYkZ5EpfvWrOtpV-",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1-IwC1Zsn5MB0-EjsRYkZ5EpfvWrOtpV-",
          "cachedResultName": "CustomCX knowledgebase folder"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "72dd042c-a4ce-4d44-a4c6-21bf7d589cfe",
      "name": "Google Drive Trigger1",
      "type": "n8n-nodes-base.googleDriveTrigger",
      "position": [
        -2384,
        1264
      ],
      "parameters": {
        "event": "fileUpdated",
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        },
        "triggerOn": "specificFolder",
        "folderToWatch": {
          "__rl": true,
          "mode": "list",
          "value": "1-IwC1Zsn5MB0-EjsRYkZ5EpfvWrOtpV-",
          "cachedResultUrl": "https://drive.google.com/drive/folders/1-IwC1Zsn5MB0-EjsRYkZ5EpfvWrOtpV-",
          "cachedResultName": "CustomCX knowledgebase folder"
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ce14ffd3-9ab1-495f-8205-b8e50c0717f4",
      "name": "Download file",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -992,
        992
      ],
      "parameters": {
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set the fields for mapping').item.json.file_id }}"
        },
        "options": {},
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "typeVersion": 3
    },
    {
      "id": "98425426-fb10-44d7-b39e-3997ce03b963",
      "name": "Supabase Vector Store",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        -752,
        992
      ],
      "parameters": {
        "mode": "insert",
        "options": {
          "queryName": "match_documents"
        },
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        }
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "2f5dd44e-2c7b-47fe-ba52-af3559c03713",
      "name": "Default Data Loader",
      "type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
      "position": [
        -768,
        1216
      ],
      "parameters": {
        "loader": "docxLoader",
        "options": {
          "metadata": {
            "metadataValues": [
              {
                "name": "file_id",
                "value": "={{ $('Set the fields for mapping').item.json.file_id }}"
              }
            ]
          }
        },
        "dataType": "binary",
        "textSplittingMode": "custom"
      },
      "typeVersion": 1.1
    },
    {
      "id": "2a75681b-a030-43f6-9ed3-da79552c80d7",
      "name": "Recursive Character Text Splitter",
      "type": "@n8n/n8n-nodes-langchain.textSplitterRecursiveCharacterTextSplitter",
      "position": [
        -688,
        1424
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "7e0a2ad8-ff38-4a48-b995-d800bbd5ef61",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1520,
        816
      ],
      "parameters": {
        "color": 7,
        "width": 1136,
        "height": 752,
        "content": "## RAG Knowledgebase\n "
      },
      "typeVersion": 1
    },
    {
      "id": "01df653e-f992-4e8a-ae87-33c8f7a1c4a9",
      "name": "Knowledgebase",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        -1424,
        496
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "options": {
          "queryName": "match_documents"
        },
        "tableName": {
          "__rl": true,
          "mode": "list",
          "value": "documents",
          "cachedResultName": "documents"
        },
        "toolDescription": "Use this tool to retrieve the knowledge about customCX"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "103d2305-c910-4c56-a462-af89daf30b02",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -1216,
        992
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "27d755a2-890e-4035-a7de-2b5c0a7414eb",
      "name": "Embeddings OpenAI",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        -992,
        1312
      ],
      "parameters": {
        "options": {
          "dimensions": 1536
        }
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "ce224928-a6bf-4945-83ac-feb262b31df2",
      "name": "Think",
      "type": "@n8n/n8n-nodes-langchain.toolThink",
      "position": [
        -944,
        480
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "d2ffa188-6ae3-46b9-8620-2f6f1fdf0960",
      "name": "Calculator",
      "type": "@n8n/n8n-nodes-langchain.toolCalculator",
      "position": [
        -1056,
        480
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "247e185b-01d1-4100-966b-f07c59b03c7b",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2688,
        880
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 720,
        "content": "### Google drive folder triggers\nThis knowledgebase pipeline allows automated update of the business data. you simply upload new documents in the google drive folder. Please note that updating a document requires you to edit the document with same ID do not upload same document twice"
      },
      "typeVersion": 1
    },
    {
      "id": "0b21d176-f31c-49ca-9acf-a4c9a5a1d77c",
      "name": "Support Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -1376,
        224
      ],
      "parameters": {
        "text": "={{ $json.chatInput }}",
        "options": {
          "systemMessage": "You are a CustomCX virtual Assistant. Your role is to help users, answer their concerns and direct them to the right place. you should be able to answer majority of there questions.\nCustomCX help businesses to automate their daily repeated workflows by Leveraging AI.\nWe implement AI solutions for Businesses that help the deliver more while spending less \n\nUse Knowledgebase tool to retrieve answers\n\nThey can also Visit our website CustomCX.com\nor contact human support at +1234567890\nWe located in Nairobi,Kenya (we work remotely but we do physical meeting at Nation Centre 9th Floor)\nBook free discovery call  https://cal.com/shadrack-customcx/30min \n\nTry to be helpful before refering our clients to human support.\n\nYou are allowed to be creative.\nAlways try to be brief and clear\n\nstrictly stick to Customcx solution context. no discussing political issues nor medical nor relationship or personal views\n\n#Rule\nYour output must never exceed 14000characters. stay in whatsapp twilio supported character limit. you may create a summary\n\n#Rule2\nYou are strictly CustomCX virtual assistant, you can Never answer questions that do not relate to CustomCX, stick to CustomCX role of workflow automation and building AI solutions.\n\nUse think tool for steps that demands logical thinking and Calculator for calculation\n\nYou must use the \"Code Tool\" to sanitize your output.  \nRemove all the asterisk no ** in the output"
        },
        "promptType": "define"
      },
      "typeVersion": 2.2
    },
    {
      "id": "1f5153db-a222-4c7f-956b-1c3a2d9fe174",
      "name": "conversation buffer",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -1536,
        480
      ],
      "parameters": {
        "sessionKey": "={{ $json.sessionId }}",
        "sessionIdType": "customKey",
        "contextWindowLength": 20
      },
      "typeVersion": 1.3
    },
    {
      "id": "c5ead51d-a0b4-4337-b1cb-665cb7f553b0",
      "name": "Deletes old records",
      "type": "n8n-nodes-base.supabase",
      "position": [
        -1792,
        1088
      ],
      "parameters": {
        "tableId": "documents",
        "operation": "delete",
        "filterType": "string",
        "filterString": "=metadata->>file_id=eq.{{ $json.file_id }}"
      },
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      },
      "executeOnce": true,
      "retryOnFail": false,
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "ef6b4a50-2125-4518-bd08-eda9125c5e1c",
      "name": "Set the fields for mapping",
      "type": "n8n-nodes-base.set",
      "position": [
        -2032,
        1088
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "32591319-9705-4dea-aacc-c6b8b8fb38e4",
              "name": "file_id",
              "type": "string",
              "value": "={{ $json.id }}"
            },
            {
              "id": "87d30657-a58a-4f3c-b59a-135511261000",
              "name": "file_name",
              "type": "string",
              "value": "={{ $json.originalFilename }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "77f1ba0b-6966-4124-bf82-6f98be0f594e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1744,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 960,
        "height": 624,
        "content": "## Website Agent\nProvide the agent with necessary tools based on your website needs like CRM"
      },
      "typeVersion": 1
    },
    {
      "id": "e38a2383-1041-4685-abb8-c5a9e1c04c81",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        -2752,
        224
      ],
      "parameters": {
        "public": true,
        "options": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "f42d9163-f850-4657-9ad3-e685272bf456",
      "name": "Code Tool",
      "type": "@n8n/n8n-nodes-langchain.toolCode",
      "position": [
        -1168,
        528
      ],
      "parameters": {
        "jsCode": "// n8n Function Node - Agent Output Sanitizer\n\nconst agentOutput = $input.item.json.output; // Adjust path to your agent output\n\nfunction sanitizeAgentOutput(text) {\n  if (!text) return '';\n  \n  let sanitized = text;\n  \n  // Remove markdown formatting\n  sanitized = sanitized.replace(/\\*\\*(.+?)\\*\\*/g, '$1'); // Bold\n  sanitized = sanitized.replace(/\\*(.+?)\\*/g, '$1'); // Italic\n  sanitized = sanitized.replace(/__(.+?)__/g, '$1'); // Underline\n  sanitized = sanitized.replace(/_(.+?)_/g, '$1'); // Italic underscore\n  sanitized = sanitized.replace(/~~(.+?)~~/g, '$1'); // Strikethrough\n  \n  // Remove markdown headers\n  sanitized = sanitized.replace(/^#{1,6}\\s+/gm, '');\n  \n  // Remove code blocks\n  sanitized = sanitized.replace(/```[\\s\\S]*?```/g, '');\n  sanitized = sanitized.replace(/`(.+?)`/g, '$1');\n  \n  // Remove markdown links but keep the text\n  sanitized = sanitized.replace(/\\[([^\\]]+)\\]\\([^\\)]+\\)/g, '$1');\n  \n  // Sanitize URLs - remove tracking parameters\n  sanitized = sanitized.replace(\n    /(https?:\\/\\/[^\\s]+)/g, \n    (url) => {\n      try {\n        const urlObj = new URL(url);\n        // Remove common tracking parameters\n        ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', \n         'fbclid', 'gclid', 'ref', 'source'].forEach(param => {\n          urlObj.searchParams.delete(param);\n        });\n        return urlObj.toString();\n      } catch {\n        return url;\n      }\n    }\n  );\n  \n  // Remove extra whitespace and newlines\n  sanitized = sanitized.replace(/\\n{3,}/g, '\\n\\n');\n  sanitized = sanitized.trim();\n  \n  return sanitized;\n}\n\n// Return sanitized output\nreturn {\n  json: {\n    sanitized: sanitizeAgentOutput(agentOutput),\n    original: agentOutput\n  }\n};"
      },
      "typeVersion": 1.3
    },
    {
      "id": "f5826529-e644-4b4d-8d7f-2b2f1487c116",
      "name": "Data Normalizer",
      "type": "n8n-nodes-base.code",
      "position": [
        -2400,
        224
      ],
      "parameters": {
        "jsCode": "// Normalize incoming data structure\nlet data = $json;\n\n// Handle nested arrays from widget\nif (Array.isArray(data) && data.length > 0) {\n  if (Array.isArray(data[0]) && data[0].length > 0) {\n    data = data[0][0];  // Double nested\n  } else {\n    data = data[0];     // Single nested\n  }\n}\n\n// Ensure we have required fields\nconst normalizedData = {\n  action: data.action || 'sendMessage',\n  sessionId: data.sessionId || '',\n  route: data.route || 'general',\n  chatInput: data.chatInput || '',\n  metadata: data.metadata || {}\n};\n\nreturn normalizedData;"
      },
      "typeVersion": 2
    },
    {
      "id": "b3b86147-19e3-4a8c-ade3-29df1111493c",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3632,
        -160
      ],
      "parameters": {
        "width": 496,
        "height": 992,
        "content": "## How it works\nThis is a website chat agent, that uniquely collect leads while supporting your website visitors. It is like a chatbot with access to some tools. It can be integrated on wordpress websites and custom buit websites. \n\nn8n supports website embedding by default, however I modified the chat widget to collect leads as meta data, the agent also do remember users from past conversations by caching their information. I also rebranded the widget to allow logo upload and creating of custom theme.\n [Sample widget](https://customcx.com/)\n\n## Setup steps\ntoggle the chat node to publicly available and mode to hosted chat\nGrab the **chat URL**  and set it up as shown below\n\n&lt;link href=\"https://cdn.jsdelivr.net/npm/@n8n/chat/dist/style.css\" rel=\"stylesheet\" /&gt;\n&lt;script&gt;\n    window.ChatWidgetConfig = {\n        webhook: {\n            url: '', // put chat URL here\n            route: 'general'\n        },\n        branding: {\n            logo: '', // your logo URL\n            name: 'CustomCX Agent',\n            welcomeText: 'Hello, how can we help?',\n            responseTimeText: 'We will get back to you soon',\n        },\n        style: {\n            primaryColor: '#854fff',\n            secondaryColor: '#6b3fd4',\n            position: 'right',\n            backgroundColor: '#ffffff',\n            fontColor: '#333333',\n        }\n    };\n&lt;/script&gt;\n&lt;script src=\"https://cdn.jsdelivr.net/gh/shadrack-ago/n8n/widget.js?v=2.6\"&gt;&lt;/script&gt;\n\npaste the above code into your index.html header or install footer and headers plugin in wordpress the paste it\n\nFind the whole repo on my GitHub account :  [Repo link](https://github.com/shadrack-ago/n8n-chat-widget)"
      },
      "typeVersion": 1
    },
    {
      "id": "03be8724-c3a0-4ebf-9f48-71c7aabed87a",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2480,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 224,
        "height": 240,
        "content": "**sanitizes the incoming input data, it ensure no empty request is sent, also it harmonises meta data and the actual chats into one output**"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Think": {
      "ai_tool": [
        [
          {
            "node": "Support Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Code Tool": {
      "ai_tool": [
        [
          {
            "node": "Support Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Calculator": {
      "ai_tool": [
        [
          {
            "node": "Support Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Download file": {
      "main": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Knowledgebase": {
      "ai_tool": [
        [
          {
            "node": "Support Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Support Agent": {
      "main": [
        []
      ]
    },
    "Data Normalizer": {
      "main": [
        [
          {
            "node": "Support Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Items": {
      "main": [
        [
          {
            "node": "Download file",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Deletes old records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Embeddings OpenAI": {
      "ai_embedding": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_embedding",
            "index": 0
          },
          {
            "node": "Knowledgebase",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Default Data Loader": {
      "ai_document": [
        [
          {
            "node": "Supabase Vector Store",
            "type": "ai_document",
            "index": 0
          }
        ]
      ]
    },
    "Deletes old records": {
      "main": [
        [
          {
            "node": "Loop Over Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "conversation buffer": {
      "ai_memory": [
        [
          {
            "node": "Support Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive Trigger": {
      "main": [
        [
          {
            "node": "Set the fields for mapping",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Drive Trigger1": {
      "main": [
        [
          {
            "node": "Set the fields for mapping",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Support Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Set the fields for mapping": {
      "main": [
        [
          {
            "node": "Deletes old records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Data Normalizer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recursive Character Text Splitter": {
      "ai_textSplitter": [
        [
          {
            "node": "Default Data Loader",
            "type": "ai_textSplitter",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow deploys a fully customizable AI chatbot that can be embedded on any website, from custom-coded sites to platforms like WordPress. The chatbot is powered by n8n, uses Supabase for memory and RAG, and integrates SerpAPI, Google Calendar, SMTP, and Google Sheets to…

Source: https://n8n.io/workflows/10365/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Your AI workforce is ready. Are you?

Google Sheets Tool, Mcp Trigger, Google Drive +29
AI & RAG

This comprehensive workflow bundle is designed as a powerful starter kit, enabling you to build a multi-functional AI assistant on Telegram. It seamlessly integrates AI-powered voice interactions, an

Telegram Trigger, Telegram, OpenAI +19
AI & RAG

This intelligent chatbot leverages cutting-edge financial APIs and AI-driven analysis to deliver comprehensive stock research reports. Get instant access to professional-grade investment analysis that

Tool Think, Supabase Vector Store, OpenAI Embeddings +15
AI & RAG

RAG_Ingest. Uses httpRequest, vectorStoreSupabase, documentDefaultDataLoader, textSplitterRecursiveCharacterTextSplitter. Event-driven trigger; 73 nodes.

HTTP Request, Supabase Vector Store, Document Default Data Loader +4
AI & RAG

This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th

OpenAI, Gmail, Text Classifier +16