{"slug": "show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website", "title": "Show HN: Bolnee-Chat – Self Hosted Chatbot Integration in Your Business Website", "summary": "Bolnee-Chat, a self-hosted RAG chatbot platform, is now available for free on GitHub, enabling businesses to integrate AI chatbots into their websites with no vendor lock-in or per-message billing. The platform supports OpenAI-compatible providers like OpenRouter, OpenAI, Groq, Ollama, and vLLM, and includes features such as website crawling, PDF ingestion, encrypted provider keys, and a dark-mode console. It runs on Node.js 18+ and Python 3.10+, with SQLite storage, and can be deployed on a server, Vercel, or Cloudflare Pages.", "body_md": "**Chatbot integration in your business website. Self hosted, free forever!**\n\nBolnee-Chat is a self-hosted RAG chatbot platform. Create a bot, add your website + PDFs as knowledge, pick any OpenAI-compatible provider (OpenRouter, OpenAI, Groq, Ollama, vLLM), and embed a 2-line snippet. Answers are grounded in your sources with citations, visitor chats are grouped and exportable, and everything runs on your infrastructure with SQLite.\n\n|\nNo vendor lock-in, no per-message billing. Run on your server, Vercel or Cloudflare Pages — SQLite, no external DB. |\nCrawls your site + ingests PDFs/TXT/MD/DOCX, chunks to SQLite FTS and builds grounded prompts. Sources are cited, fallback is configurable. |\nCopy |\n\n**Also in the box:**\n\n**Knowledge management**— lists`locator · type · status · error · date`\n\nwith delete; append more via**Add knowledge**.** Avatar file storage**— data URLs converted to`/api/public/avatar/:id`\n\n(2MB limit,`data/avatars/`\n\n).**Encrypted provider keys**— per-bot`apiKey/baseUrl/model`\n\nvia AES-256-GCM, never exposed in snippet.**Dark-mode console**—`#020617`\n\nbg,`#1e293b`\n\ncards,`slate-800`\n\ninputs, no white surfaces.\n\n| Requirement | Details |\n|---|---|\nOS |\nmacOS, Linux, Windows (WSL) |\nRuntime |\nNode.js 18+ |\nPackage Manager |\nnpm |\nPython |\n3.10+ (crawler, optional but recommended) |\nPython Deps |\n`aiohttp` , `beautifulsoup4` , `lxml` , `requests` , `brotli` (+ `playwright` for JS-heavy sites) |\n\n```\n# Clone\ngit clone https://github.com/AniketWathore/bolnee-chat.git\ncd bolnee-chat\n\n# Env\ncp .env.example .env\n# edit .env — simplest self-hosted:\n# DISABLE_AUTH=true\n# JWT_SECRET=change-me-32-chars\n# LLM_BASE_URL=https://openrouter.ai/api/v1   # optional global fallback\n# LLM_API_KEY=sk-or-v1-...                     # optional global fallback\n# LLM_MODEL=inclusionai/ling-3.0-flash-fin:free\n\n# Install\nnpm install\n\n# Python crawler deps (optional)\npip install aiohttp beautifulsoup4 lxml requests brotli\n\n# Verify\nnpm run lint    # tsc --noEmit\nnpm run build   # vite + esbuild → dist/\nnpm run dev     # http://localhost:3000 (auto-fallback to 3001 if busy)\n```\n\nSQLite is created at `data/bolnee.db`\n\n(git-ignored). Crawled sites → `data/{chatbotId}_website.json`\n\n, chunks in SQLite.\n\n**Create chatbot**—`+ New chatbot`\n\n→ name + avatar (preview ≤2MB).**Add knowledge**— enter`https://your-site.com`\n\nand/or upload PDF/TXT/MD/DOCX/FAQ → status`queued → indexed`\n\n.**Configure provider**— choose provider →`Fetch models`\n\n→ pick model → Save. Keys encrypted, not in embed.**Embed**— copy snippet from`Overview`\n\n:\n\n```\n<script>\n  window.BotConfig = {\n    botName: \"Customer Bot\",\n    avatar: \"https://your-domain/api/public/avatar/BOT_ID\",\n    chatUrl: \"https://your-domain/api/public/chat/BOT_ID\",\n    accentColor: \"#111111\",\n    greeting: \"Hi! How can I help?\",\n    theme: \"dark\"\n  };\n</script>\n<script src=\"https://your-domain/chatbot-widget.js\" async></script>\n```\n\nPaste before `</body>`\n\n. Widget stores `VISITOR_ID`\n\n+ chat history in `localStorage`\n\n; greeting shows once.\n\n| Tab | What it does |\n|---|---|\nOverview |\nLive status, messages/users/sources, embed copy (`src/components/ChatbotDashboard.tsx:244` ) |\nAppearance |\n`name/avatar/accent/theme/greeting` + live preview (`src/components/ChatbotDashboard.tsx:282` ) |\nChats |\nGrouped by visitor → date, `CSV/JSON/PDF` , `Refresh` (`src/components/ChatbotDashboard.tsx:371` ) |\nKnowledge |\nSources + `Add knowledge` wizard (`src/components/ChatbotDashboard.tsx:449` ) |\nSettings |\n`provider/model/baseUrl/apiKey` , `defaultMessage/fallbackMessage` , `Danger zone` delete (`src/components/ChatbotDashboard.tsx:493` ) |\n\n| Method | Path | Description |\n|---|---|---|\n`POST` |\n`/api/chatbots` |\nCreate bot |\n`GET` |\n`/api/chatbots` |\nList bots |\n`PATCH` |\n`/api/chatbots/:id` |\nAppearance + provider (`name/avatar/accent/theme/greeting` + `provider/model/apiKey/baseUrl` ) |\n`GET` |\n`/api/chatbots/:id/appearance` |\nGet appearance (`server.ts:728` ) |\n`GET` |\n`/api/chatbots/:id/messages?limit=200` |\nGrouped messages |\n`GET` |\n`/api/chatbots/:id/stats` |\n`total/users` |\n`GET` |\n`/api/chatbots/:id/messages/export?format=csv|json` |\nExport |\n`GET` |\n`/api/knowledge/sources?chatbotId=ID` |\nList sources |\n`POST` |\n`/api/knowledge/sources/:chatbotId` |\nAdd URL (`{url}` ) or file (`multipart` ) → `queued` |\n`DELETE` |\n`/api/knowledge/sources/:sourceId?chatbotId=ID` |\nDelete source + chunks |\n`POST` |\n`/api/public/chat/:chatbotId` |\nSSE chat `{message, visitorId}` → `data: {token|error|sources}` + `data: [DONE]` |\n`GET` |\n`/api/public/knowledge/:chatbotId` |\nPublic knowledge (cached) |\n`GET` |\n`/api/public/avatar/:chatbotId` |\nAvatar file or redirect |\n`POST` |\n`/api/providers/models` |\nList models for `provider/baseUrl/apiKey` |\n`GET` |\n`/api/stats` |\nGlobal `totalMessages/activeSessions` |\n\nStreaming: `public/chatbot-widget.js:311`\n\nreads SSE via `getReader()`\n\n, falls back to `text()`\n\n+ SW bypass for `locked`\n\nstreams. Visitor grouping via `X-Visitor-Id`\n\n(`VISITOR_ID`\n\nin `localStorage`\n\n).\n\n| Path | Role |\n|---|---|\n`server.ts` |\nExpress + Vite dev, auth (`DISABLE_AUTH` ), ingestion, RAG, SSE chat (`server.ts:282` ) |\n`server/db.ts` |\nSQLite (`better-sqlite3` ) — `chatbots/sources/chunks/messages` , `getChatbotAppearance` |\n`server/ingestion.ts` + `crawler/run_crawler_for_bolnee.py` |\nCrawl → `/data/{id}_website.json` → chunks |\n`crawler/crawler.py` |\nSame-origin crawl, `robots.txt` , `h1/h2/p/li` extraction, sitemap + homepage |\n`public/chatbot-widget.js` |\nEmbeddable widget — `BotConfig.chatUrl` , accent, greeting, theme, `VISITOR_ID` , history |\n`src/components/ChatbotDashboard.tsx` |\nTabs: overview/appearance/chats/knowledge/settings, `embedCode` with `theme` |\n`src/components/KnowledgeSection.tsx` |\n4-step wizard: Knowledge → Provider → Processing (polls status) → Embed |\n`src/components/Overview.tsx` |\nStats + grid of 4 bots + `View all` |\n`src/components/BotCreationWizard.tsx` |\nName + avatar upload (2MB limit) |\n`src/index.css` |\nDark-mode tokens (`--color-bg #020617` , `--color-card #1e293b` ) |\n`vercel.json` / `wrangler.toml` |\nHosting rewrites, `bucket = \"./dist\"` , `DISABLE_AUTH` |\n\nDashboard is fully API-driven (`/api/*`\n\nrelative) and auto-configures `window.location.origin`\n\nfor embed URLs.\n\n**Vercel:**\n\n```\n# env\nDISABLE_AUTH=true\n# JWT_SECRET not required for simple mode\n\n# vercel.json already: rewrites /api/:path* → /api, /(.*) → /index.html, outputDirectory: dist\nnpm run build && vercel --prod\n```\n\n**Cloudflare Pages / Workers:**\n\n```\n# wrangler.toml: bucket = \"./dist\", DISABLE_AUTH=true\nnpm run build\nwrangler pages deploy dist\n# or: npx wrangler deploy\n```\n\nChat endpoint streams SSE; for external sites use public `https://`\n\n`chatUrl`\n\n(not `localhost`\n\n).\n\n| Env | Description | Default |\n|---|---|---|\n`DISABLE_AUTH` / `VITE_DISABLE_AUTH` |\nNo-login console (single-tenant) | `false` |\n`JWT_SECRET` |\nAuth signing key (16+ chars, prod required) | `development-secret-change-me` |\n`LLM_BASE_URL` / `OPENROUTER_API_KEY` / `NVIDIA_API_KEY` |\nGlobal provider fallback (per-bot settings take precedence) | — |\n`LLM_API_KEY` |\nGlobal API key fallback | — |\n`LLM_MODEL` |\nGlobal model fallback (e.g. `openai/gpt-4o-mini` ) |\n`gpt-4o-mini` |\n`PORT` |\nServer port (auto-fallback `+1` if busy) |\n`3000` |\n\n`.env.example`\n\ndocuments all.\n\n| Symptom | Fix |\n|---|---|\nPort `3000 in use → 3001` and embed fails on external site |\nEmbed uses `window.location.origin` ; regenerate after restart or deploy to public URL (localhost embed is `https://` mixed-content) |\n`getReader locked` / `ReadableStream locked` |\nBump `public/sw.js` to `v3` skips `POST /api/public/chat` ; hard-refresh to update SW |\nModel `404` / `402` |\nUse Fetch models → pick `:free` (e.g. `inclusionai/ling-3.0-flash-fin:free` ) or add credits |\n`404` knowledge/avatar |\nEnsure `data/bolnee.db` exists and bot `id` matches `data/{id}_website.json` |\n| Avatar too large | PNG/JPG/WEBP ≤2MB; data URLs auto-converted to `/api/public/avatar/:id` |\n| Greeting repeats on open/close | Fixed in `public/chatbot-widget.js:115` — `saveHistory/loadHistory` in `localStorage` + `engine=true` guard; clear `bolnee_msgs_*` to reset |\n\n```\nnpm run lint      # tsc --noEmit clean\nnpm run build     # vite + esbuild → dist/\nnpm run dev       # http://localhost:3000\n# Manual:\n# 1. Create bot → avatar preview → Save appearance → preview updates\n# 2. Add knowledge: URL + PDF → status queued → indexed\n# 3. Provider → Fetch models → pick :free → Save\n# 4. Overview → Copy embed → paste in plain HTML → widget loads, greeting once, close/open keeps history, dark/light/auto themes correct\n# 5. Chats → grouped by visitor → CSV/JSON/PDF export\n# 6. Settings → default/fallback messages → Chat without sources returns fallback\n```\n\nDistributed under the [MIT License](/AniketWathore/bolnee-chat/blob/main/LICENSE). See [ LICENSE](/AniketWathore/bolnee-chat/blob/main/LICENSE) for more information.", "url": "https://wpnews.pro/news/show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website", "canonical_source": "https://github.com/AniketWathore/bolnee-chat", "published_at": "2026-08-30 09:56:05+00:00", "updated_at": "2026-08-30 10:21:59.038213+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-products", "ai-tools", "generative-ai"], "entities": ["Bolnee-Chat", "OpenRouter", "OpenAI", "Groq", "Ollama", "vLLM", "Vercel", "Cloudflare Pages"], "alternates": {"html": "https://wpnews.pro/news/show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website", "markdown": "https://wpnews.pro/news/show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website.md", "text": "https://wpnews.pro/news/show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website.txt", "jsonld": "https://wpnews.pro/news/show-hn-bolnee-chat-self-hosted-chatbot-integration-in-your-business-website.jsonld"}}