notebooklm-py: The Reverse-Engineered NotebookLM That Turns Google’s Research App Into a Programmable Engine
An unofficial Python SDK and CLI exposes hidden exports, bulk automation, and agent-ready workflows by decoding Google’s internal RPC protocol.
- notebooklm-py is most interesting as a bridge between a closed AI product and an open automation layer, not as a generic SDK.
- The repo’s real edge is that it exposes NotebookLM’s product-level outputs, including artifacts and exports, not just chat access.
- Its hardest engineering problem is the undocumented RPC layer, where nested request shapes and brittle responses have to be normalized into usable Python.
- The project is built for agents as much as for humans, which makes it feel more like infrastructure than a one-off wrapper.
Most unofficial APIs imitate a web app. notebooklm-py does something sharper. It treats NotebookLM as a finished research engine and then teaches Python, CLIs, and even other AIs how to drive it.
That is why the repo matters. It is not simply a convenience wrapper around Google’s research product. It is a translation layer between a polished consumer interface and the undocumented machinery underneath it.
NotebookLM, but callable
The practical leap is easy to miss. With this repo, NotebookLM stops being a browser-only destination and becomes something you can script, schedule, chain, and delegate. The difference shows up in the details: notebooks, sources, chats, artifacts, exports, and bulk automation all become callable operations.
That makes the project useful to two audiences at once. Developers get a Python SDK and CLI. Agents get a skill-shaped interface they can consume without needing to understand the whole product by hand.
How could NotebookLM become fully programmable? A new community project, notebooklm-py, exposes an unofficial Python API for Google’s Google NotebookLM—unlocking automation and workflows that the web UI doesn’t support.
The hidden value is not the API, it is the product
The reason this repo lands so well is that it targets a product shape, not a model endpoint. NotebookLM is already opinionated. It knows how to ingest sources, ground answers, and emit artifacts that feel like a research workflow instead of a blank canvas.
That makes the unlock more valuable than raw model access. You are not just calling an LLM. You are borrowing a packaged workflow that already knows how to turn sources into useful outputs.
| Option | What you start with | What you must build | Why it matters |
|---|---|---|---|
| Direct NotebookLM use | A polished UI | Everything manual | Good for one-off research, poor for automation |
| Official Google AI APIs | Raw model access | Retrieval, storage, orchestration, artifact logic | Flexible, but you assemble the workflow yourself |
| LangChain or LlamaIndex | A general RAG framework | Product shape, UX, export logic, NotebookLM-like behaviors | Powerful, but broad and heavier to finish |
| notebooklm-py | NotebookLM’s finished workflow | Only your automation around it | Fastest path to NotebookLM-shaped research pipelines |
The point of the table is simple. notebooklm-py is narrower than a general stack, but that narrowness is the feature. It skips the work of rebuilding a product that already knows how to behave like a research assistant.
The engine room: Google’s internal RPC shape
This is the center of the repo. Google’s NotebookLM backend does not behave like a tidy REST service. The library has to speak in the shape Google expects, which means encoding requests into a nested batchexecute format and decoding responses that arrive wrapped in noise, prefixes, and multiple layers of arrays.
At the request level, the code has to build shapes like [[[method_id, json_params, null, "generic"]]]. On the response side, it has to remove anti-XSS prefixes and walk nested structures until the actual payload appears. That is not glamorous work, but it is the entire reason the SDK can exist.
# Conceptual shape, simplified
request = encode_rpc_request(
method_id="someMethod",
params={"notebook_id": notebook_id, "source_ids": source_ids},
)
raw = await client.post("/batchexecute", content=request)
payload = decode_rpc_response(raw)
# payload is now usable Python data, not Google's wrapper format
The design choice here is deeper than protocol trivia. By isolating the translation logic, the repo makes a hostile backend feel like a normal dependency. That is what turns reverse engineering into a maintainable tool.
Why the client is split into sub-APIs
The top-level client stays thin on purpose. NotebookLM behavior is divided into domain modules for sources, notebooks, artifacts, chat, and other surfaces. That structure keeps the codebase from collapsing into a single giant wrapper file every time Google adds a new feature.
This is one of the repo’s strongest maturity signals. Reverse-engineered projects usually accrete hacks. This one is organized as if it expects to live through change.
client = NotebookLMClient(auth=auth)
client.sources.import_urls([...])
client.chat.ask("Summarize the common themes")
client.artifacts.download_mind_map(notebook_id)
client.notebooks.list()
# The facade stays small.
# The behavior lives in sub-APIs.
That split also makes the project easier to extend. A new artifact type or source workflow can land in its own module without forcing every other path to know about it.
Authentication is the real long-term tax
Unofficial APIs do not fail politely. Sessions expire. Cookies go stale. CSRF tokens drift. Regional cookie domains can change the shape of login state. This repo treats auth as a first-class system instead of an afterthought.
That matters more than it sounds. A scriptable product is only useful if it can survive the messy middle of long-running automation. Otherwise it is just a demo.
| Problem | What breaks | How notebooklm-py responds |
|---|---|---|
| Session expiry | Requests start failing mid-run | A refresh callback can reroute into re-authentication |
| Cookie handling | Login state is incomplete or region-specific | The auth layer tracks cookies and regional domain edge cases |
| CSRF drift | Valid sessions stop being accepted | The client refreshes the token instead of assuming it remains stable |
| Browser login | Headless setup becomes brittle | Playwright-assisted login captures the initial session more reliably |
That is the difference between a hack and infrastructure. The project knows the backend is unstable, so it builds systems around the instability instead of pretending it is not there.
Built for agents, not just developers
The most forward-looking move in the repo is not a method. It is the packaging. With SKILL.md and AGENTS.md, notebooklm-py is written so another AI can consume it as a tool.
That changes the mental model. The repo is no longer only a library for humans writing Python. It is also a downstream component in an AI toolchain, something Claude Code or another agent can call when it needs grounded research, artifact generation, or exports.
仕組みはシンプル: 1. notebooklm-pyをインストール(Teng LingがリバースエンジニアリングしたCLI) 2. Claude CodeにSkillとして認識させる 3. ClaudeがNotebookLMに研究をオフロード 4. トークン消費なしで30文書以上を分析可能 GoogleのGeminiが処理するからハルシネーションも少ない。 https://t.co/63GUyvXS6Q
That is a real shift. The tool stops being just an API consumer and becomes a capability that other AI systems can route work through.
Why this is sturdier than it sounds
The repo’s credibility comes from defensive engineering. Tests use vcrpy cassettes so behavior can be replayed without hammering Google’s servers. Linting, typing, packaging, and integration boundaries are all treated as serious concerns.
That does not make the unofficial API safe. It makes it disciplined. In a world where the backend can change under your feet, discipline is the difference between a useful tool and a maintenance nightmare.
| Signal | What it tells you | Why it matters |
|---|---|---|
| vcrpy tests | Recorded network interactions are part of the workflow | The team expects unstable external behavior and plans for it |
| mypy and ruff | Typing and linting are enforced | The codebase is meant to stay readable as it grows |
| hatchling packaging | Modern Python build flow | Release mechanics are not improvised |
| docs on RPC development | Reverse-engineering knowledge is documented | The hardest part is shared, not hidden in one maintainer’s head |
That last point is important. Documenting the RPC shape is a form of resilience. It makes the project easier to keep alive when the product changes.
What notebooklm-py replaces, and what it does not
This repo is not a replacement for every RAG stack. It will not give you the flexibility of a blank-slate retrieval system. It will not replace the broad ecosystem around LangChain or LlamaIndex. It is much more specific than that.
What it does replace is a lot of glue work. If your goal is NotebookLM-shaped research workflows, notebooklm-py gives you a shortcut into an already good product surface. That is a different value proposition from building a system from scratch.
| Approach | Best for | Trade-off |
|---|---|---|
| notebooklm-py | NotebookLM-shaped research automation | Depends on an undocumented Google backend |
| Official Google AI APIs | Custom application building | You assemble the product behavior yourself |
| LangChain or LlamaIndex | General RAG systems | More flexibility, more setup, more decisions |
| Direct NotebookLM UI | Manual analysis and ad hoc use | No programmable workflow |
That is the right way to read the repo. It is not trying to become the universal abstraction. It is trying to make one especially good product programmable.





