←  All projects Open Source · Shipped

DocuSage

A self-hosted AI chatbot that answers from your own PDF documents — embeddable on any website with one script tag. Your infrastructure, your API keys, your data. MIT licensed, and you can clone it right now.

Type Open-source product
Licence MIT
Stack TypeScript · React · Express · Postgres
Read ~8 min

The ideaSearch our PDFs, but it actually works

A lot of "add AI to our website" requests are really one request underneath: let people ask questions about our documents and get a straight answer. DocuSage is that, built as something you run yourself rather than something you rent.

You upload your manuals, policies or product sheets. DocuSage extracts the text, splits it into chunks, computes embeddings, and answers questions with retrieval-augmented generation — grounded in your documents rather than in whatever the model happens to remember. Then you drop the chatbot onto your site with a single script tag.

The part that matters

You run your own instance, on your own infrastructure, with your own API keys. Your documents and your customers' questions never pass through anyone else's service — there is no SaaS in the middle and no per-conversation pricing.

PipelineIngest once, answer grounded

Two paths run through the system. Ingestion happens once per document; the query path runs on every question and never touches the model until it has real chunks to work with.

INGESTION — RUNS ONCE PER DOCUMENT PDF upload multer Text extraction pdfExtractor Chunking documentProcessor Embeddings per chunk Postgres drizzle QUERY — RUNS ON EVERY QUESTION Question embed widget Embed query same model Semantic search top-k chunks Generate answer grounded in context Reply + disclaimer chunks + embeddings read back at query time Failure detection logs questions it could not answer Analytics what docs lack The gap log is the useful part: it tells you which questions your documentation does not answer yet. The model is never asked to invent the missing answer.
Ingestion runs once per document; the query path runs per question. Retrieval happens before generation, so the model only ever sees text that actually exists in your documents — and when nothing relevant comes back, that gets logged rather than papered over.

IntegrationOne script tag, no cookies

The whole integration is a single tag. The project detail page generates it for you:

<script src="https://your-domain.com/embed.js"
  data-token="<project-token>"
  data-color="blue"
  data-theme="light"
  data-style="classic"
  data-chatbot-name="DocuSage Assistant"
  data-welcome-message="Hello, how can I help you?"
  data-disclaimer-text="Answers are generated by AI and may not always be accurate."
></script>

Three looks ship out of the box — classic, advanced and premium — switched with the data-style attribute. The widget sets no cookies and authenticates purely with the project token, so it works from any domain without a tracking script tagging along.

BuildBoring stack, on purpose

Nothing here is exotic. That is the point: a self-hosted product is only useful if the person deploying it can actually understand and operate it.

LayerChoiceWhy
FrontendReact + TypeScript on Vite, Tailwind with ShadCN UI, Wouter for routing, TanStack Query for server stateFast builds, typed end to end, and a component layer that is easy to restyle for whoever deploys it.
BackendNode 20+ with Express, TypeScript ES modulesOne language across the whole repo, and a runtime that runs anywhere without ceremony.
DatabasePostgreSQL 14+ with Drizzle ORM, schema shared between client and serverType-safe queries, one migration path, and the schema is a single source of truth rather than two drifting copies.
AuthPassport local strategy, bcrypt password hashing, sessions in a Postgres storeSessions survive a restart, and there is no third-party identity provider to sign up for before you can log in.
DocumentsMulter upload, server-side PDF text extraction, chunking and embedding in a dedicated service layerIngestion is isolated behind its own module, so swapping the chunking strategy does not touch the API.
HostingNeon serverless driver for *.neon.tech, plain PostgreSQL connection for everything elseDetected from the connection string, so a managed database and a VPS both work with no config switch.

ModelsNot tied to one vendor

The AI provider is chosen per project, not globally: OpenAI, Google Gemini or Azure OpenAI, each with its own model selection and API key. A team running one chatbot on Azure for compliance reasons and another on Gemini for cost reasons is a supported configuration, not a fork.

That mattered for a self-hosted tool more than it would for a SaaS. Whoever deploys DocuSage already has a vendor relationship, an approved-supplier list, or a region requirement — hardcoding one provider would rule out a large share of the people the project is for.

ScopeWhat's in the box

// 01

Multi-project, multi-tenant

Separate chatbots, documents, teams and API keys. Role-based access with hierarchical team permissions, so one instance serves more than one part of an organisation.

// 02

REST API

Documented public API with per-project tokens and call tracking, for when the embed widget is not the integration you want.

// 03

Analytics & the gap log

Usage analytics plus a log of the questions the chatbot could not answer — which doubles as a to-do list for your documentation.

// 04

Customisable without forking

Prompts live in one file, theming in CSS custom properties, and branding, language and colours are documented in their own customisation guide.

OpsThree documented deployment targets

Azure App Service, Google Cloud Run, and a plain VPS — all three written up in the README, with a production build verified to start from a clean install. Requirements are deliberately small: Node 20+, a PostgreSQL 14+ database, and one API key. SMTP is optional, and the README is explicit that without it account activation and password reset will not work.

Operator responsibility, stated up front

The README has a section most side projects skip: if you deploy DocuSage for other people, you are the operator and the data controller. GDPR obligations, what gets sent to your chosen AI provider and where, keeping a visible AI disclaimer, and replacing the placeholder marketing copy — all spelled out before you go live, rather than discovered afterwards.

PracticeTreated like a real product

BoundariesWhat it deliberately isn't

The README says out loud who should not use this, which I think is the more honest half of a project page:

Both constraints keep the scope small enough that the thing actually works, ships and stays maintainable — which is worth more than a longer feature list.

In one sentence

Upload your PDFs, get a grounded chatbot on your site with one script tag — running on your own infrastructure, with your own keys.

Free and open source under MIT. Clone it, deploy it, change the prompts, ship it commercially — just keep the licence text.

Open Source

Clone it,
run your own

MIT licensed. Node 20, a Postgres database and one API key is the whole shopping list — the README takes you from clone to running instance.

View on GitHub