Open NotebookLM
by mkshaonexe
README.md
# Open NotebookLM
Use **your own signed-in Google NotebookLM account** (now called *Gemini Notebook*, notebook.google.com)
from AI agents, scripts and the terminal, with no GUI. It works as an **MCP server**, a **CLI**, a local
**REST API** and an **OpenAI-compatible API**.
You sign in once in a normal Chrome window. After that, Open NotebookLM keeps a hidden Chrome tab and calls
the same internal endpoints the NotebookLM web app calls, from inside that tab. Your agent can do everything
a person does in the UI: create notebooks, add sources, chat with citations, run Deep Research, and make
Audio/Video Overviews, slide decks, quizzes, flashcards, mind maps, infographics, reports and data tables,
then download them. It never asks for your password, and no cookies leave your browser.
```
your agent ──MCP / CLI / REST / OpenAI──▶ open-notebooklm (127.0.0.1:2791) ──▶ hidden Chrome tab on notebook.google.com
```
> **AI agents:** read [`skills/open-notebooklm/SKILL.md`](skills/open-notebooklm/SKILL.md). It covers setup, every
> tool, recipes and limits. Give your agent this repo's link and it can set itself up.
## What it can do
Everything below was tested end to end against a live Google AI Pro account in October 2026. The two
exceptions are sharing with another person (not tested, to avoid emailing anyone) and retrying a failed
output (no output failed during testing).
| | CLI | MCP tool (`notebooklm_…`) |
|---|---|---|
| List / create / rename / copy / delete notebooks | `notebooks`, `create`, `rename`, `copy`, `delete` | `list_notebooks`, `create_notebook`, … |
| Notebook summary + suggested questions | `summary`, `prompts` | `notebook_summary`, `suggest_prompts` |
| Add web pages, YouTube, files (PDF, DOCX, PPTX, MD, TXT, CSV, EPUB, images, audio, video), pasted text, Google Drive | `add <nb> <url\|file>… --text … --drive <id>` | `add_sources` |
| Read a source's full text, its AI guide, search passages | `source`, `guide`, `search` | `get_source`, `source_guide`, `search_sources` |
| Rename / remove / re-sync sources | `rename-source`, `remove-source`, `refresh` | `rename_source`, `delete_source`, `refresh_source` |
| **Fast & Deep Research** (web or Drive), import results + report | `research <nb> "…" [--deep] [--drive]` | `research`, `research_status`, `import_research` |
| **Chat** grounded in sources, numbered citations, follow-ups, multi-turn | `ask <nb> "…"` | `ask` |
| Chat history, clear history, custom persona / length | `history`, `clear-chat`, `configure` | `chat_history`, `clear_chat`, `configure_chat` |
| **Audio Overview** (Deep Dive, Brief, Critique, Debate; short/default/long) → `.m4a` | `generate <nb> audio` | `generate` |
| **Video Overview** (Explainer, Brief, Short, Cinematic*; 9 visual styles) → `.mp4` | `generate <nb> video` | `generate` |
| **Slide deck** (detailed / presenter) → `.pdf` / `.pptx`, revise one slide | `generate <nb> slide_deck`, `revise-slide` | `generate`, `revise_slide` |
| **Infographic** (3 orientations, 3 detail levels, 11 styles) → `.png` | `generate <nb> infographic` | `generate` |
| **Report** (Briefing Doc, Study Guide, Blog Post, custom, suggested) → `.md` | `generate <nb> report`, `report-ideas` | `generate`, `suggest_reports` |
| **Quiz** / **Flashcards** (quantity, difficulty) → `.json` / `.html` | `generate <nb> quiz` / `flashcards` | `generate` |
| **Mind map** → JSON tree | `generate <nb> mind_map` | `generate` |
| **Data table** → `.csv`, export to Google Sheets | `generate <nb> data_table -i "…"` | `generate`, `export_artifact` |
| List / read / wait / download / rename / delete / retry outputs | `artifacts`, `artifact`, `wait`, `download`, … | `list_artifacts`, `get_artifact`, `download_artifact`, … |
| Export reports to Google Docs, tables to Sheets | `export [--sheets]` | `export_artifact` |
| Notes: list, add, edit, delete | `notes`, `add-note`, `edit-note`, `delete-note` | `list_notes`, `create_note`, … |
| Sharing: people, public link, chat-only view | `share` | `share_status`, `share`, `set_public`, `set_view_level` |
| AI source labels | `labels [--auto]` | `list_labels`, `auto_label` |
| Plan, limits, **live usage meter**, output language | `account`, `usage`, `language` | `account`, `usage`, `set_language` |
\* Cinematic video needs Google AI Ultra. What each plan allows: [docs/plans-and-limits.md](docs/plans-and-limits.md).
How it was reverse-engineered: [docs/how-it-works.md](docs/how-it-works.md).
## Before you use it
- This is unofficial and not affiliated with Google. It automates notebook.google.com with your own login.
Use it on your own account for personal use. Google can change its internal API at any time.
- It uses your account's real quotas (for example, about 3 Audio Overviews a day on the free plan).
- Files you pass are local paths on the machine running Open NotebookLM. It only listens on 127.0.0.1.
## Setup
Needs Node.js 20+ and Google Chrome (or Chromium). Set `CHROME_PATH` if Chrome isn't in the usual place.
```bash
git clone https://github.com/mkshaonexe/open-notebooklm.git
cd open-notebooklm
npm install
npm link # optional: puts `open-notebooklm` (alias `notebooklm`) on your PATH
```
**1. Sign in once.** A Chrome window opens on NotebookLM; sign in to Google the normal way:
```bash
open-notebooklm login
```
The session is kept in `~/.open-notebooklm/chrome-profile`, a separate Chrome profile only Open NotebookLM uses.
**2. Use it.** Every command works on its own (it starts a hidden Chrome when needed), or start the server
once and keep it running:
```bash
open-notebooklm serve # hidden Chrome; --show to see the window
```
It prints the URL and your local API key (`open-notebooklm key` prints the key again).
## CLI
`<nb>` is a notebook id or part of its title.
```bash
open-notebooklm notebooks
open-notebooklm create "Solar research"
open-notebooklm add "Solar" https://en.wikipedia.org/wiki/Solar_power https://youtu.be/xKxrkht7CpY ./notes.pdf \
--text "Bangladesh has 6M+ solar home systems." --title "My note"
open-notebooklm research "Solar" "solar panel recycling methods" --deep # finds + imports sources and a report
open-notebooklm ask "Solar" "What are the main challenges?" # answer + [1] [2] citations
open-notebooklm summary "Solar"
open-notebooklm generate "Solar" audio --format debate --length short -o podcast.m4a # waits, then downloads
open-notebooklm generate "Solar" video --format explainer --style whiteboard -o video.mp4
open-notebooklm generate "Solar" slide_deck --format presenter_slides -o deck.pdf
open-notebooklm generate "Solar" infographic --orientation portrait --style kawaii -o info.png
open-notebooklm generate "Solar" report --format study_guide -o guide.md
open-notebooklm generate "Solar" quiz --quantity more --difficulty hard -o quiz.json
open-notebooklm generate "Solar" flashcards --wait
open-notebooklm generate "Solar" mind_map -o map.json
open-notebooklm generate "Solar" data_table -i "compare each technology by efficiency and cost" -o table.csv
open-notebooklm artifacts "Solar" # every output and its status
open-notebooklm download "Solar" <artifact_id> -o deck.pptx --format pptx
open-notebooklm export "Solar" <report_id> # → Google Docs link (--sheets for data tables)
open-notebooklm revise-slide "Solar" <deck_id> 2 "Make this a 3-bullet summary"
open-notebooklm sources "Solar" ; source "Solar" <source_id> ; search "Solar" "perovskite"
open-notebooklm notes "Solar" ; add-note "Solar" "Idea" "Check IDCOL data"
open-notebooklm share "Solar" --public # --private, --add a@b.com --role viewer, --chat-only
open-notebooklm usage # live 5-hour / weekly meter
open-notebooklm account # plan, limits, output language
```
Long commands print progress on stderr (`… generating audio (in_progress) (40s)`; `--quiet` hides it).
`--json` prints the full result. Without `-o`/`--wait`, `generate` returns at once with the artifact id.
## MCP
**stdio** (simplest: it starts the hidden Chrome itself, or forwards to a running `serve`):
```bash
claude mcp add notebooklm -- node /path/to/open-notebooklm/bin/cli.js mcp
```
```json
{ "mcpServers": { "notebooklm": { "command": "node", "args": ["/path/to/open-notebooklm/bin/cli.js", "mcp"] } } }
```
(after `npm link`: `"command": "open-notebooklm", "args": ["mcp"]`)
**Streamable HTTP** (with `serve` running):
```bash
claude mcp add --transport http notebooklm http://127.0.0.1:2791/mcp \
--header "Authorization: Bearer $(open-notebooklm key)"
```
51 tools, all prefixed `notebooklm_`. The full list with arguments is in
[SKILL.md](skills/open-notebooklm/SKILL.md). Long tools (`ask`, `add_sources`, `research`, `generate`,
`wait_for_artifact`, `download_artifact`) send **MCP progress notifications** when the client passes a
`progressToken`. Failures come back as error results that name the step and the reason, for example
`Failed while generating audio: NotebookLM usage limit reached for this account (5-hour window resets …)`.
## Agent skill
[`skills/open-notebooklm/SKILL.md`](skills/open-notebooklm/SKILL.md) is a standard agent skill. Copy the
`skills/open-notebooklm` folder into your agent's skills directory (for Claude Code: `~/.claude/skills/`),
or just point your agent at this repository: [`AGENTS.md`](AGENTS.md) tells it where to start.
## REST
Every route except `/health` needs `Authorization: Bearer <key>`. The API is one route per method:
`POST /api/<method>` with the method's options as a JSON body (camelCase). The CLI and the MCP server
use the same methods.
```bash
KEY=$(open-notebooklm key)
curl -s localhost:2791/api/listNotebooks -H "authorization: Bearer $KEY" -d '{}'
curl -s localhost:2791/api/ask -H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"notebookId":"<id>","question":"Summarise the sources in 3 bullets"}'
curl -s localhost:2791/api/generate -H "authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"notebookId":"<id>","type":"audio","format":"brief","wait":true}'
```
| Group | Methods |
|---|---|
| Account | `status`, `account`, `usage`, `setLanguage {language}`, `progress` |
| Notebooks | `listNotebooks`, `createNotebook {title}`, `getNotebook`, `renameNotebook {title}`, `deleteNotebook`, `copyNotebook {title}`, `summary`, `suggestPrompts {query}`, `configureChat {goal, customPrompt, length}` |
| Sources | `addSources {urls, files, text, title, driveId, driveMimeType, wait}`, `listSources`, `getSource {sourceId, format}`, `sourceGuide`, `searchSources {query, sourceIds}`, `renameSource`, `deleteSource {sourceId \| sourceIds}`, `refreshSource`, `waitForSources` |
| Research | `research {query, mode, corpus, wait, importSources}`, `researchStatus {taskId}`, `importResearch {taskId, urls}`, `cancelResearch` |
| Chat | `ask {question, sourceIds, fresh}`, `chatHistory {limit}`, `clearChat` |
| Studio | `generate {type, instructions, sourceIds, language, format, length, style, stylePrompt, quantity, difficulty, orientation, detail, wait}`, `listArtifacts {type}`, `getArtifact`, `waitForArtifact`, `downloadArtifact {outFile, format}`, `renameArtifact`, `deleteArtifact`, `exportArtifact {to}`, `reviseSlide {slide, instructions}`, `retryArtifact`, `suggestReports`, `studioOptions` |
| Notes | `listNotes`, `createNote {title, content}`, `updateNote {noteId, title, content}`, `deleteNote` |
| Sharing | `shareStatus`, `setPublic {public}`, `share {email, role, notify, message}`, `setViewLevel {level}` |
| Labels | `listLabels`, `autoLabel {onlyUnlabeled}`, `deleteLabel {labelId}` |
All notebook-scoped methods take `notebookId`.
## OpenAI-compatible API
Each notebook is a "model". Answers are grounded in that notebook's sources, and the citations are listed
at the end of the reply.
```python
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:2791/v1", api_key="<open-notebooklm key>")
print([m.id for m in client.models.list()]) # notebook:<id> for every notebook
r = client.chat.completions.create(model="notebook:<notebook_id>",
messages=[{"role": "user", "content": "What do my sources say about X?"}])
print(r.choices[0].message.content)
```
Only the newest user message is sent; the notebook keeps its own chat history.
## Files and settings
Everything lives in `~/.open-notebooklm/` (override with `OPEN_NOTEBOOKLM_HOME`):
| Path | |
|---|---|
| `chrome-profile/` | the signed-in Chrome profile |
| `config.json` | API key and settings (below) |
| `downloads/<notebook_id>/` | outputs downloaded without `-o` |
| `config.json` key | Default | |
|---|---|---|
| `port` | `2791` | API port (env `OPEN_NOTEBOOKLM_PORT`) |
| `cdpPort` | `9341` | Chrome debugging port, bound to 127.0.0.1 |
| `chromePath` | per OS | env `CHROME_PATH` |
| `baseUrl` | `https://notebook.google.com` | env `OPEN_NOTEBOOKLM_BASE_URL` (enterprise: `https://notebook.cloud.google.com`) |
| `language` | account setting | default output language for generated outputs |
| `waitTimeoutMs` | `1800000` | how long `wait` waits for an output |
If Google renames an internal RPC id, you can patch it without a new release:
`OPEN_NOTEBOOKLM_RPC_OVERRIDES='{"LIST_NOTEBOOKS":"newId"}'` (names are in `src/rpc.js`).
## Credits
Built with the capture-the-traffic approach of [reverse-api-engineer](https://github.com/kalil0321/reverse-api-engineer).
The RPC map was cross-checked against the excellent reverse-engineering notes of
[notebooklm-py](https://github.com/teng-lin/notebooklm-py) (MIT), and every call was verified against the live site.
Same pattern as [open-chatgpt](https://github.com/mkshaonexe/open-chatgpt).
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues