Newsletter image

Subscribe to the Newsletter

Join 10k+ people to get notified about new posts, news and tips.

Do not worry we don't spam!

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Search

GDPR Compliance

We use cookies to ensure you get the best experience on our website. By continuing to use our site, you accept our use of cookies, Privacy Policy, and Terms of Service.

n8n - Automation

Build a Website Knowledge Chatbot With n8n (No Vector Database Needed)

You do not need a vector database to put a useful AI chatbot on your website. If your knowledge fits in a folder of markdown files, an n8n agent can read the right file on demand and a small script drops the chat window onto any page.

You do not need a vector database to put a useful AI chatbot on your website. If your knowledge fits in a folder of markdown files, an n8n agent can read the right file on demand and answer from it, and a small JavaScript snippet drops the chat window onto any page. This is the fastest path from "I have some docs" to "there is a chatbot on my site that knows them," and it runs entirely on your own machine.

This is the first of a two part thread in the n8n Automation Stack series. Here we build the simple version: markdown files as the knowledge base, a chat widget on your site. The follow up swaps the markdown lookup for a Supabase vector database when your knowledge outgrows a handful of files. If you are new to n8n, start with what n8n is and how to install it.

What You Are Building

Three pieces, wired together in one n8n workflow:

Piece n8n node Job
Knowledge base Files on disk One markdown file per topic in a shared folder
Lookup tool Sub-workflow + Tool node Reads the file the agent asks for and returns its text
Brain AI Agent + Chat model Picks a document, reads it, answers the question
Front door Chat Trigger A public webhook the website chat widget talks to

No embeddings, no database migrations. The agent does keyword-level reasoning over whole documents, which is plenty when you have a dozen or two well-named files.

Prerequisites

You need a running n8n with a local model runtime. The easiest way to get both, plus everything the follow up article needs, is the bundled stack we covered in our local-ai-packaged guide. It brings up n8n, Ollama, and Postgres together in one command. Pull a small instruct model once it is running:

ollama pull qwen2.5:7b-instruct-q4_K_M

That is the model doing the talking in this build. Anything in the 7B to 14B instruct range works; smaller is faster, larger follows instructions more reliably.

Step 1: The Knowledge Base Is Just Files

Create a folder that n8n can read and drop one markdown file per topic into it. n8n containers usually mount a shared directory at /data/shared, so a clean layout looks like this:

/data/shared/mysite/docs/
  getting-started.md
  pricing.md
  returns-policy.md
  api-authentication.md

The file name is the lookup key, so name files after the questions people ask. There is no ingestion step and nothing to rebuild. Edit a file, save it, and the next answer uses the new text. That immediacy is the whole appeal of this approach.

Step 2: A Sub-Workflow That Reads One Document

The agent should not touch the filesystem directly. Instead, build a small second workflow that takes a document name and returns its text, then hand that workflow to the agent as a tool. Keeping it separate means the agent can only read files through this one narrow door, and you can test the door on its own.

The sub-workflow is three nodes behind an Execute Workflow Trigger whose input is a single field, document:

{
  "nodes": [
    { "name": "When Called", "type": "n8n-nodes-base.executeWorkflowTrigger" },
    { "name": "Build File Path", "type": "n8n-nodes-base.set" },
    { "name": "Read Document", "type": "n8n-nodes-base.readWriteFile" },
    { "name": "Extract Text", "type": "n8n-nodes-base.extractFromFile" }
  ]
}

The Set node turns the document name into a safe path. Sanitising the name matters: it stops the agent from walking out of your docs folder with a crafted value. Use an expression on a single string field named filePath:

=/data/shared/mysite/docs/{{ $json.document.toLowerCase().replace(/[^a-z0-9_-]/g, '-') }}.md

Read Document points at {{ $json.filePath }}, and Extract Text runs in text mode so the output is plain markdown the model can read. That is the entire tool.

Step 3: The Agent

Now the main workflow. Drop in an AI Agent node and give it three attachments: a chat model, a memory, and the tool you just built.

  • Chat model: an Ollama Chat Model node pointed at qwen2.5:7b-instruct-q4_K_M.
  • Memory: a Simple Memory (or Postgres Chat Memory) node with Session ID set to From input, so each website visitor keeps their own conversation.
  • Tool: a Call n8n Workflow Tool node pointing at the sub-workflow from step 2. Name it lookup_document and describe it clearly.

The description is what the agent reads to decide when to call the tool, so it earns its keep. A system prompt on the agent ties it together:

You answer questions about MySite using a document library.
Available documents: getting-started, pricing, returns-policy, api-authentication.
To answer, call lookup_document with the single most relevant document name,
then answer only from what it returns. If no document fits, say so plainly.
Never invent product details.

Listing the available document names in the prompt is the trick that makes file-based lookup work. The model maps the question to a file, calls the tool, and answers from the returned text.

Step 4: The Front Door

Replace any manual trigger with a Chat Trigger node (When chat message received). This node is what the website widget talks to. Two settings matter:

Setting Value Why
Make Chat Publicly Available On The widget calls it from a browser with no n8n login
Allowed Origins (CORS) https://yoursite.com Only your site may open the chat; blocks everyone else

Leave the response mode at the default so the Chat Trigger streams the agent's answer straight back to the widget. Turn off Append n8n Attribution in the node options for a clean embed. Activate the workflow, then open the node and copy its chat URL. It has this shape:

https://your-n8n-host/webhook/<chat-webhook-id>/chat

Test it from n8n's built-in chat panel before touching your website. Ask something that should hit a document and confirm the agent calls lookup_document and answers from the file.

Step 5: Put the Chat on Your Website

n8n publishes an official chat widget, @n8n/chat, under an MIT license. You load it from a CDN and initialise it with one function call. Add this to any page:

<link href="https://cdn.jsdelivr.net/npm/@n8n/chat/dist/style.css" rel="stylesheet">
<script type="module">
  import { createChat } from 'https://cdn.jsdelivr.net/npm/@n8n/chat/dist/chat.bundle.es.js';

  createChat({
    webhookUrl: 'https://your-n8n-host/webhook/<chat-webhook-id>/chat',
    mode: 'window',
    chatInputKey: 'chatInput',
    chatSessionKey: 'sessionId',
    showWelcomeScreen: false,
    initialMessages: ['Hi! Ask me anything about MySite.'],
    i18n: {
      en: {
        title: 'Ask us',
        subtitle: '',
        inputPlaceholder: 'Type your question...',
        getStarted: 'New conversation'
      }
    }
  });
</script>

That is the exact shape a real deployment uses. A few options are worth understanding:

Option Effect
webhookUrl The Chat Trigger URL from step 4. This is the only required option.
mode window gives a floating bubble in the corner; fullscreen mounts the chat into a target element.
chatSessionKey Must match the Chat Trigger. The widget generates a session id so returning visitors keep context, which is why the agent memory used From input.
initialMessages / i18n The greeting bubble and the widget labels. Set them to your brand voice.

If the widget loads but every message fails, the cause is almost always CORS. The origin you are embedding on must be listed in the Chat Trigger's Allowed Origins. That single field is the most common reason a working chat looks broken on the live site.

Where This Runs Out of Road

File-based lookup is honest about what it is. The agent matches the question to a file name and reads the whole file, so it works best when documents are short, topics are cleanly separated, and there are not too many of them. Past roughly a few dozen files, listing every name in the system prompt stops being practical and the model starts guessing the wrong file.

It also cannot answer across documents or find a paragraph buried in a long one. There is no semantic search, only whole-file retrieval. When you hit that wall, you do not throw this away: you keep the same agent, the same Chat Trigger, and the same website embed, and you swap the file-reading tool for a vector search tool. That is exactly what part two does with Supabase and embeddings.

Sources and Further Reading

Next in the series: scaling this chatbot with a Supabase vector database, so it can search thousands of documents by meaning instead of matching file names. The website widget does not change. Only the tool behind it does.

The workflow

Prev Article
Turn an n8n Workflow Into an MCP Tool Your AI Agent Can Call
Next Article
Scale Your n8n Chatbot With a Supabase Vector Database (RAG)

Related to this topic: