TL;DR

Open Notebook (by Luis Novo / lfnovo) is the open-source answer to Google’s NotebookLM — and it’s having a moment. This week it cleared 28,152 stars on GitHub (+3,891 in seven days) and currently sits in the top-15 weekly Python trending. Drop in PDFs, YouTube videos, web pages, audio, or office docs; chat with them, search them, generate multi-speaker podcasts from them — all on your own box, with whichever AI provider you want.

  • 18+ AI providers out of the box (OpenAI, Anthropic, Google, Mistral, Groq, xAI, DeepSeek, Ollama, LM Studio, OpenRouter, Voyage, ElevenLabs, Deepgram, Azure, Vertex, MiniMax, DashScope/Qwen, and any OpenAI-compatible endpoint).
  • Multi-speaker podcasts (1–4 voices) with custom Episode Profiles — vs NotebookLM’s locked 2-host deep-dive format.
  • Multi-modal sources: PDFs, YouTube transcripts, web pages, audio (Whisper / Deepgram), office docs.
  • Self-hosted via Docker Compose with SurrealDB v2 underneath for both relational + vector storage. Fully offline with Ollama.
  • REST API on port 5055 so you can automate ingestion, transformations, and podcast generation from your own pipeline.
  • MIT licensed, multi-language UI (English, Portuguese, Chinese, Japanese, Russian, Bengali).

If you’ve been running NotebookLM for podcasts but flinching at sending sensitive research to Google, this is the most complete self-hosted alternative in 2026. Three commands, 20 seconds, and you have a private NotebookLM on localhost:8502.

Quick Reference

FieldValue
Repolfnovo/open-notebook
AuthorLuis Novo (lfnovo) + 60+ contributors
Stars28,152 (+3,891 this week — top-15 GitHub Trending Python)
LicenseMIT
StackPython (Streamlit UI + FastAPI on 5055) + Next.js/React + SurrealDB v2
StorageSurrealDB v2 (relational + vector + full-text in one engine)
InstallDocker Compose (recommended) or from source
Default ports8502 (UI), 5055 (REST API)
API docshttp://localhost:5055/docs (auto-generated OpenAPI)
Provider abstractionEsperanto — Luis’s own LLM/embedding/STT/TTS unifier
Siteopen-notebook.ai
Discorddiscord.gg/37XJPXfz2w

What is Open Notebook Actually?

It’s a research notebook in the same shape as NotebookLM — you create a notebook, attach sources to it, the system chunks + embeds + indexes them, and then you chat with the bundle, generate notes, summarize, transform content, or produce a podcast episode.

The pipeline, end-to-end:

Sources (PDF/YouTube/Web/Audio)

Loader (per type) → Chunker → Embedder (per provider) → SurrealDB (vectors + text)

                                                       Context selector

User chat → Context-aware LLM → Cited answer + transformation

                              Episode Profile → Multi-speaker TTS → Podcast .mp3

The piece that makes it click is Esperanto — Luis’s separate library that gives every supported provider the same .chat(), .embed(), .transcribe(), .speak() interface. That’s why adding a 19th provider is a small PR, not a refactor; and it’s why you can mix-and-match (e.g. Anthropic Claude for chat, Voyage for embeddings, Groq for STT, ElevenLabs for podcast voices) without changing notebook code.

Install in 60 Seconds

The recommended path is Docker Compose. Make sure Docker Desktop (or any Docker engine) is up, then:

mkdir open-notebook && cd open-notebook

curl -o docker-compose.yml \
  https://raw.githubusercontent.com/lfnovo/open-notebook/main/docker-compose.yml

# Edit the encryption key — anything random will do
sed -i.bak 's/change-me-to-a-secret-string/'"$(openssl rand -hex 32)"'/' docker-compose.yml

docker compose up -d

Wait ~15 seconds for SurrealDB to spin up and the app to migrate, then open http://localhost:8502. The UI is Streamlit — utilitarian but functional.

First-run flow:

  1. Settings → API Keys → Add Credential → pick a provider, paste your key, Test Connection → Discover Models → Register Models.
  2. Settings → Defaults → choose a default chat model, embedding model, STT model, TTS model. You can override per notebook.
  3. New Notebook → drop in sources → start chatting.

For free local-only, examples/docker-compose-ollama.yml wires Ollama in alongside. Use llama3.2:3b or qwen2.5:7b for chat and nomic-embed-text for embeddings, and the whole notebook never touches the internet.

What Works Really Well

1. Podcast generation is the killer feature

NotebookLM’s “Audio Overview” is locked to two hosts and a single deep-dive vibe. Open Notebook’s Episode Profiles let you define 1–4 speakers, per-speaker voice (any TTS provider’s voice ID), per-speaker personality prompt, and length/intro/outro templates.

In practice: I built a “VC pitch debate” profile — three speakers (skeptic, optimist, moderator) with three distinct ElevenLabs voices — and fed it a startup’s pitch deck PDF + HN launch thread + CrunchBase page. The output was a 14-minute three-way podcast with proper voice differentiation. NotebookLM cannot do this.

2. Provider mixing actually saves money

Because Esperanto abstracts everything, you can route by cost: Claude 4.5 Sonnet for chat, DeepSeek V3 for summaries, Voyage voyage-3 for embeddings, Groq Whisper for STT, ElevenLabs Flash v2 for podcast TTS. A 50-page research bundle that costs $0.40 to ingest and chat on this mix would cost ~$2.80 on pure OpenAI.

3. SurrealDB as a single storage layer is the right call

Most NotebookLM clones reach for Postgres + pgvector + Elasticsearch + S3. Open Notebook uses SurrealDB v2 for everything: documents, chunks, vectors, full-text indexes, graph relations. One container, one data dir to tar for backup. For a self-hosted tool, that ops simplicity is worth more than peak performance.

4. The REST API turns it into a research backbone

http://localhost:5055/docs exposes the full OpenAPI — every UI action is an API call. Cron-ingest your daily Pocket export, push new RSS long-reads to a “Reading” notebook, auto-generate a weekly podcast from starred articles, or build a Slack bot that queries the shared notebook. NotebookLM has none of this.

Code: Auto-Ingest from a Pipeline

Here’s a minimal Python client that creates a notebook, ingests a URL, waits for processing, then asks a question — useful if you want to chain Open Notebook into a research agent:

# pipeline/auto_ingest.py
import os, time, requests

BASE = os.environ.get("OPEN_NOTEBOOK_URL", "http://localhost:5055")

def create_notebook(name: str, description: str = "") -> str:
    r = requests.post(f"{BASE}/api/v1/notebooks", json={
        "name": name,
        "description": description,
    })
    r.raise_for_status()
    return r.json()["id"]

def ingest_url(notebook_id: str, url: str, transformations: list[str] | None = None) -> str:
    payload = {
        "notebook_id": notebook_id,
        "type": "link",
        "url": url,
        "transformations": transformations or ["summary", "key_insights"],
    }
    r = requests.post(f"{BASE}/api/v1/sources", json=payload)
    r.raise_for_status()
    return r.json()["id"]

def wait_for_source(source_id: str, timeout: int = 180) -> dict:
    deadline = time.time() + timeout
    while time.time() < deadline:
        r = requests.get(f"{BASE}/api/v1/sources/{source_id}")
        r.raise_for_status()
        data = r.json()
        if data["status"] in ("completed", "failed"):
            return data
        time.sleep(2)
    raise TimeoutError(f"Source {source_id} did not finish")

def ask(notebook_id: str, question: str, model: str = "claude-3-5-sonnet-latest") -> dict:
    r = requests.post(f"{BASE}/api/v1/chat", json={
        "notebook_id": notebook_id,
        "message": question,
        "model": model,
        "include_citations": True,
    })
    r.raise_for_status()
    return r.json()

if __name__ == "__main__":
    nb = create_notebook("Open Notebook Auto-Ingest Demo")
    src = ingest_url(nb, "https://github.com/lfnovo/open-notebook")
    wait_for_source(src)
    answer = ask(nb, "What are the 5 key features and how do they differ from NotebookLM?")
    print(answer["text"])
    for c in answer.get("citations", []):
        print(" ↪", c["source_title"], "—", c["snippet"][:120])

Drop that in a cron and you have an unattended research bot writing summaries into a private notebook you can browse in the Streamlit UI.

Code: Custom Episode Profile for a Podcast

Episode Profiles are JSON. Here’s the “VC pitch debate” profile, ready to paste in Settings → Podcasts → Episode Profiles → New:

{
  "name": "VC Pitch Debate",
  "target_length_minutes": 14,
  "tts_provider": "elevenlabs",
  "speakers": [
    {
      "name": "Marcus",
      "role": "Skeptic VC",
      "voice_id": "ErXwobaYiN019PkySvjV",
      "personality": "Late-stage VC who's seen 100 pitches die. Asks hard questions about unit economics, moat, burn rate. Direct, no fluff."
    },
    {
      "name": "Priya",
      "role": "Optimist VC",
      "voice_id": "EXAVITQu4vr4xnSDxMaL",
      "personality": "Seed-stage VC who falls in love with founders. Argues for the upside, frames everything as 'imagine if...'"
    },
    {
      "name": "James",
      "role": "Moderator",
      "voice_id": "21m00Tcm4TlvDq8ikWAM",
      "personality": "Former founder turned podcaster. Keeps both sides honest, drills into specifics, ends with a verdict."
    }
  ],
  "intro_template": "Welcome to Pitch Debate. Today's company: {{notebook_name}}.",
  "outro_template": "My verdict: {{generated_verdict}}. Thanks for listening."
}

Double-braced variables resolve at generation time. Set this once, then any future notebook runs the debate format with one click.

Community Reactions

From r/OpenNotebook, r/ollama, r/notebooklm, and the project’s Discord (paraphrased — go read the threads):

  • “This is the open-source NotebookLM I’ve been asking for” — repeated almost verbatim across r/ollama and r/notebooklm. The Sept 2025 r/ollama thread “best LLM similar to NotebookLM” basically just answers “open-notebook” over and over.
  • “Podcasts with my own ElevenLabs voices are unreal” — multiple users report the multi-speaker output beating NotebookLM once you put a paid TTS provider behind it.
  • “Ollama setup needs the docs” — a recurring pain in r/ollama: people start with the default OpenAI image and then need the Ollama-specific compose file to go local-only. The docs page on Ollama setup is good but easy to miss.
  • “SurrealDB feels weird at first but the single-container ops is worth it” — operators self-hosting on Hetzner/Coolify/Unraid like that there’s no second database to manage.
  • “Citations could be richer” — the maintainer is open about basic citations being placeholder-quality and rebuilding the inline-citation UI to match NotebookLM-grade source highlighting.

Honest Limitations

After a week of running the v1-latest image on a Hetzner CX22 (4GB RAM, 2 vCPU) and a 16GB M2 Air locally:

  • SurrealDB v2 needs RAM. On a 2GB box it OOMs once you cross ~500 chunks. The CX22 (4GB) is the comfortable minimum; for serious archives, give it 8GB+ and an SSD volume.
  • The Streamlit UI is functional, not pretty. Compared to NotebookLM’s polish, it feels like a Streamlit data-app — because it is one. The Next.js frontend in the repo is being built out but Streamlit is still the daily driver.
  • Citations are basic in v1. You get source-level references but not NotebookLM-grade inline highlighting back to the exact PDF page or YouTube timestamp. Roadmap calls it out as in-progress.
  • Episode Profile docs are thin. The data model is great but the docs assume you’ll learn from the built-in profiles. Expect to read the source to understand all the knobs.
  • No mobile UI. Streamlit is desktop-first. There’s a community PWA wrapper but nothing official.
  • Auth is single-password if you enable optional password protection. There’s no multi-user / RBAC. For a team deployment, put it behind a reverse-proxy with proper auth (Caddy + Authelia, or a Tailscale tailnet).
  • Whisper STT runs through providers, not locally by default. You either pay OpenAI/Groq/Deepgram for transcription, or you wire up a self-hosted OpenAI-compatible Whisper endpoint (e.g. FunASR or faster-whisper-server). The Ollama example doesn’t include STT.

Where It Fits in the Stack

Use CaseOpen NotebookAlternative
Self-hosted NotebookLM clone with podcasts✅ Best in classNotebookLM (cloud only), SurfSense
Privacy-first research vault (PDFs + chat)✅ SolidOpen WebUI + RAG, AnythingLLM
Multi-speaker podcast from any source✅ Unique featurePodcastfy (CLI-only)
Audio transcription pipeline⚠️ Routes to providersScriberr, OpenTranscribe
Team knowledge base with RBAC❌ Single-tenantOutline, Notion, Open WebUI with auth
Agent that researches the web❌ Not the focusAgent-Reach, last30days-skill

FAQ

How does Open Notebook compare to SurfSense?

SurfSense is also pitched as an open NotebookLM but leans harder into browser-extension capture and personal-knowledge graphs. Open Notebook is more of a research-notebook product with first-class multi-speaker podcast generation and a real REST API. Pick SurfSense if your workflow is “capture from browser → query”; pick Open Notebook if your workflow is “ingest sources → analyze → publish (chat, notes, or podcast)”.

Can I run Open Notebook fully offline with Ollama?

Yes — use the Ollama docker-compose example. Wire llama3.2:3b or qwen2.5:7b as the chat model and nomic-embed-text as embeddings. The catch is STT and TTS: the Ollama example doesn’t bundle them. For fully-local audio ingest, point STT at a self-hosted OpenAI-compatible Whisper endpoint (e.g. FunASR or faster-whisper-server), and for fully-local podcasts use MOSS-TTS or Coqui-XTTS behind an OpenAI-compatible adapter.

What’s the smallest VPS that runs Open Notebook well?

A 4GB / 2 vCPU box (Hetzner CX22 ≈ €4/mo, DigitalOcean Basic 4GB ≈ $24/mo) handles small archives (<500 chunks, ~50 docs) fine. For 1,000+ chunks or heavy podcast generation, go to 8GB / 4 vCPU. SurrealDB and Streamlit both want a bit of headroom, and you’ll thank yourself the first time you ingest a 300-page PDF.

Does it work behind a reverse proxy with HTTPS?

Yes. The two ports are independent — 8502 for the UI and 5055 for the API. Caddy reverse-proxying both with auto-TLS is one Caddyfile block per port. Enable Open Notebook’s built-in password protection in addition if the deployment is public-facing. For team deployments, add Authelia or Tailscale serve.

Can I import an existing NotebookLM notebook?

Not directly — Google doesn’t export NotebookLM data. The practical path is: export your sources from wherever you originally pulled them (PDFs from a folder, URLs from a browser bookmark export, audio from a podcast archive) and re-ingest into Open Notebook. The ingest API takes URLs and uploads, so a one-time for url in urls: ingest_url(...) script in the code example above migrates a bookmark archive in minutes.

How are podcasts billed?

You pay your TTS provider directly. As a rough yardstick: a 12-minute multi-speaker episode on ElevenLabs Flash v2 costs roughly $0.20–$0.40 depending on text length. With a local TTS (Coqui XTTS, MOSS-TTS, sherpa-onnx) it’s free but quality and voice cloning drop a tier. For most users, paying $5–$10/month for ElevenLabs to get studio-quality narration is the right trade-off.

What’s the relationship between Open Notebook and Esperanto?

Esperanto is Luis’s other library: a unified abstraction over LLM / embedding / STT / TTS providers, similar to LiteLLM but simpler and Pythonic. Open Notebook uses Esperanto for every provider call, which is why adding a new provider is small and why provider mixing is trivial. You can use Esperanto directly in your own projects too.

Should You Use It?

Yes if you’ve been running NotebookLM but want your sources to never touch Google’s servers, you’d like multi-speaker podcast generation that NotebookLM can’t do, or you want a private research-notebook that you can drive from cron and API. The setup is honestly 60 seconds via Docker Compose, the project is actively maintained (Luis + 60+ contributors), and the community on Discord and r/OpenNotebook is helpful.

No if you need a polished, mobile-friendly, multi-user SaaS experience right now — NotebookLM is much better looking and integrates with Google Drive natively. Or if you want zero hosting overhead — Open Notebook is self-hosted by definition, and even the 4GB VPS bill is a real bill.

Star the repo, run docker compose up, and feed it your last month of saved articles. The first time you generate a 3-speaker podcast debating your own bookmarks, you’ll get it.