Files
teng-lin--notebooklm-py/docs/installation.md
T
wehub-resource-sync 09e9f3545f
CodeQL / Analyze (push) Waiting to run
dependency-audit / pip-audit (push) Waiting to run
Test / Code Quality (push) Waiting to run
Test / Test (macos-latest, Python 3.10) (push) Blocked by required conditions
Test / Test (macos-latest, Python 3.11) (push) Blocked by required conditions
Test / Test (macos-latest, Python 3.12) (push) Blocked by required conditions
Test / Test (macos-latest, Python 3.13) (push) Blocked by required conditions
Test / Test (macos-latest, Python 3.14) (push) Blocked by required conditions
Test / Test (ubuntu-latest, Python 3.10) (push) Blocked by required conditions
Test / Test (ubuntu-latest, Python 3.11) (push) Blocked by required conditions
Test / Test (ubuntu-latest, Python 3.12) (push) Blocked by required conditions
Test / Test (ubuntu-latest, Python 3.13) (push) Blocked by required conditions
Test / Test (ubuntu-latest, Python 3.14) (push) Blocked by required conditions
Test / Test (windows-latest, Python 3.10) (push) Blocked by required conditions
Test / Test (windows-latest, Python 3.11) (push) Blocked by required conditions
Test / Test (windows-latest, Python 3.12) (push) Blocked by required conditions
Test / Test (windows-latest, Python 3.13) (push) Blocked by required conditions
Test / Test (windows-latest, Python 3.14) (push) Blocked by required conditions
chore: import upstream snapshot with attribution
2026-07-13 13:30:13 +08:00

38 KiB
Raw Blame History

Installation

Last Updated: 2026-07-11

This is the canonical installation guide for notebooklm-py. The README has a quickstart; everything else lives here.

Contents


Prerequisites

  • Python 3.10 or later. Tested and classified for 3.10, 3.11, 3.12, 3.13, 3.14. The CLI hard-fails with a clear error on older versions (see _version_check.py).
  • Operating systems. macOS (primary development platform), Linux (Debian/Ubuntu, Fedora), Windows 10/11, WSL.
  • uv (optional but recommended for contributors). Install with curl -LsSf https://astral.sh/uv/install.sh | sh or brew install uv / winget install astral-sh.uv. End users can use plain pip or pipx.
  • Disk and bandwidth. Base install is small (~10 MB). The first notebooklm login downloads Chromium (~170 MB; 3090 s; no progress bar — be patient).

Quick install (TL;DR by persona)

Installing the CLI on macOS / Linux — use an isolated installer. Plain pip install into the system interpreter fails on modern macOS (Homebrew Python) and Debian/Ubuntu with error: externally-managed-environment (PEP 668). For CLI/app use, prefer uv tool install or pipx install — they put notebooklm (and notebooklm-mcp / notebooklm-server) on your PATH in a dedicated environment without touching system Python. Plain pip still works inside a virtualenv and on Windows (python.org's Python is not externally-managed). Library users install into their own project's venv (uv add / pip install), so PEP 668 never applies.

Persona Install command
A — AI Agent pip install "notebooklm-py[browser]" in the user's active env (fall back to uv tool install / pipx install on an externally-managed-environment error)
B — End user uv tool install "notebooklm-py[browser]" or pipx install "notebooklm-py[browser]" (isolated; avoids the PEP 668 error)
C — Library user uv add notebooklm-py (or pip install notebooklm-py inside your project venv)
D — Headless server / CI pip install notebooklm-py inside a venv/container; ship a storage_state.json (no Playwright)
E — Contributor uv sync --frozen --extra browser --extra dev --extra markdown && uv run playwright install chromium && uv run pre-commit install
F — Power user uv tool install --python 3.12 "notebooklm-py[browser,cookies,markdown]" (the cookies extra needs Python ≤ 3.12; --python 3.12 makes uv provision a matching interpreter even if your default is 3.13+)

Choose your install path

A. AI Agent (primary persona)

For Claude Code, Codex, and similar agent harnesses.

The project ships notebooklm skill install, SKILL.md, and AGENTS.md. Agents run install on the user's behalf in the user's existing environment — no new venv. They typically can't interact with a browser, but most agent harnesses (Claude Code, Codex) can shell out to Playwright when a user is present, and [cookies] is a preferred optimization for reusing the user's already-logged-in browser cookies.

Note on agent harness coverage: notebooklm skill install empirically writes to ~/.claude/skills/notebooklm/SKILL.md and ~/.agents/skills/notebooklm/SKILL.md. Cursor and other harnesses with bespoke skill formats are not auto-targeted; they fall back to pip install + manual skill registration.

Recommended install (Python-version-aware; surfaces real errors instead of swallowing them):

pip install "notebooklm-py[browser]"   # mandatory; errors must propagate

# [cookies] (rookiepy) is optional and known to FAIL TO BUILD on Python 3.13+.
# Skip it deliberately on 3.13+ rather than swallowing the error — that lets
# *real* install failures (typos, network, PyPI outages) surface for the agent.
if python -c "import sys; sys.exit(0 if sys.version_info < (3, 13) else 1)"; then
    pip install "notebooklm-py[cookies]"   # errors propagate
else
    echo "Skipping [cookies] on Python 3.13+ (rookiepy unavailable). Use 'notebooklm login' interactively."
fi

If pip install errors with externally-managed-environment (modern macOS / Debian system Python, PEP 668), retry with uv tool install "notebooklm-py[browser]" or pipx install "notebooklm-py[browser]" — isolated installs that don't touch system Python. Inside an active virtualenv, pip works as-is.

Why two separate calls (not [browser,cookies]): the combined form is atomic — if rookiepy fails to compile, the whole install fails and the user gets nothing. Splitting means [browser] always succeeds; [cookies] is recoverable.

Skill install (separate from the Python package):

notebooklm skill install              # writes to ~/.claude/skills/, ~/.agents/skills/
# OR (alternative ecosystem):
npx skills add teng-lin/notebooklm-py

If the agent is reading SKILL.md from inside an already-installed location (e.g. ~/.claude/skills/notebooklm/SKILL.md), the skill is already present — you only need the Python package install + auth.

Authentication — notebooklm login is the primary path:

notebooklm login                       # primary: opens browser, user signs in to Google once

After login, storage_state.json persists at ~/.notebooklm/profiles/default/storage_state.json and is reused on every subsequent run. Verify with notebooklm auth check --test --json (require "status": "ok" AND "checks.token_fetch": true — bare auth check --json only proves the file parses, not that the cookies still authenticate against Google).

Headless / sandboxed agent contexts (no display, can't open a browser): use the cookie-extraction path instead, requires the [cookies] extra installed in step 2:

notebooklm login --browser-cookies auto    # rookiepy autodetects an installed browser

If the agent is in a no-display sandbox AND [cookies] isn't installed (Python 3.13+ skipped it), ask the user to run notebooklm login on a workstation and copy the resulting ~/.notebooklm/profiles/default/storage_state.json to the agent's environment (or set NOTEBOOKLM_AUTH_JSON).

Sandboxed agents (Claude Cowork)

Claude Cowork (Anthropic's sandboxed desktop agent for non-developers) and similar no-display sandboxes are a special case of the headless path above: there is no browser for notebooklm login, and the sandbox resets between sessions. Two adjustments make everything except login work:

  • Bootstrap each session with the base install — [browser]/Playwright is not needed here, only for login (which you run elsewhere, once):
    pip install notebooklm-py    # queries/generation/download need no extras
    
  • Reuse a host-generated storage_state.json. Run notebooklm login once on a machine with a display, then bring the file into a sandbox-accessible folder. Point at it with the root --storage flag or NOTEBOOKLM_AUTH_JSON — the same mechanism as Persona D:
    notebooklm --storage /path/to/storage_state.json list             # per-invocation flag
    # OR inline via env var (no file needed — e.g. from a Cowork-stored secret):
    export NOTEBOOKLM_AUTH_JSON="$(cat /path/to/storage_state.json)"
    notebooklm list
    

⚠️ Security: storage_state.json and NOTEBOOKLM_AUTH_JSON are bearer credentials for your Google account — store the file 0600 or in the sandbox's secret store, never commit or log them, and unset NOTEBOOKLM_AUTH_JSON after use.

Pass an explicit -n/--notebook <id> on notebook-scoped commands — the selected-notebook context does not survive a session reset. If Cowork reads ~/.claude/skills/, notebooklm skill install registers the skill there; otherwise build the uploadable archive on the host with notebooklm skill package (writes notebooklm-skill.zip; see cli-reference.md) and add it via Claude Settings → Capabilities.

Verification (machine-parseable):

notebooklm --version                    # text version
notebooklm auth check --json            # JSON: {"status": "ok", "checks": {...}}
notebooklm auth check --test --json     # same + network token-fetch validation
notebooklm list --json                  # JSON list (may be empty for new accounts)

Important: notebooklm status is context state (selected notebook), NOT auth. Do not grep its output for auth signals.

Error strings the agent should grep:

  • "Playwright not installed" → install [browser]
  • "rookiepy" (in stderr of pip install) → expected on Python 3.13+; skip [cookies] and use interactive notebooklm login
  • "status": "ok" (in auth check --json) → auth file present and parses; pair with --test for network validation

B. End user

Occasional CLI use.

Prerequisites: Python 3.10+ already installed.

Recommended — isolated install (macOS / Linux / Windows):

uv tool install "notebooklm-py[browser]"
# OR, with pipx:
pipx install "notebooklm-py[browser]"

Both put notebooklm on your PATH in a dedicated environment, so they work even where the system Python is locked down — modern macOS (Homebrew) and Debian/Ubuntu reject a plain pip install into it with error: externally-managed-environment (PEP 668). (If you don't have uv yet: https://docs.astral.sh/uv/getting-started/installation/.)

Plain pip is fine inside a virtualenv, or on Windows (python.org's Python is not externally-managed):

pip install "notebooklm-py[browser]"

Post-install: Run notebooklm login once. The CLI auto-installs Chromium on first run (~170 MB, 3090 s, no progress bar — be patient).

Verify:

notebooklm --version
notebooklm login                  # opens Chromium for Google sign-in
notebooklm auth check --test      # confirms auth roundtrip, with explicit success message

C. Library user

Embedding notebooklm-py in a Python application.

Recommended: pip install notebooklm-py (in your app's venv).

Post-install: None for runtime use. To programmatically run interactive login from your app, add [browser] and run playwright install chromium.

Why no extras by default: all RPC traffic uses httpx; auth is cookie-based (src/notebooklm/auth.py). Apps can ship a pre-generated storage_state.json and never touch Playwright.

Verify:

import notebooklm
print(notebooklm.__version__)

Production deployment patterns (tracked in #417). Production-grade FastAPI/Django integration — client lifetime in a lifespan handler, httpx pool sizing, behavior under concurrent CSRF refresh, multi-tenant storage_state.json rotation, a service-shaped Dockerfile, and structured rate-limit/backoff patterns — is not yet covered in docs/python-api.md. These were intentionally deferred from the install-docs consolidation (PR #416) to keep its scope focused. See #417 for the gap inventory and acceptance criteria.

D. Headless server or CI

Recommended: pip install notebooklm-py

Post-install (3-step recipe — Playwright is not required on the server):

  1. On a workstation with a display, install with [browser] and log in once:

    pip install "notebooklm-py[browser]"
    playwright install chromium
    notebooklm login   # writes ~/.notebooklm/profiles/default/storage_state.json
    
  2. Move the auth file to the server. Either ship it as a file:

    scp ~/.notebooklm/profiles/default/storage_state.json \
        user@server:~/.notebooklm/profiles/default/storage_state.json
    

    or stuff the contents into a CI / deployment env var (preferred for ephemeral runners):

    export NOTEBOOKLM_AUTH_JSON="$(cat ~/.notebooklm/profiles/default/storage_state.json)"
    

    CI env-var notes:

    • storage_state.json is typically 415 KB — well under GitHub Actions' 48 KB single-secret cap.
    • Watch for trailing newlines: pipe with tr -d '\n' if your secret-set tool adds one (cat ... | tr -d '\n' | gh secret set NOTEBOOKLM_AUTH_JSON).
    • For ephemeral runners (GitHub Actions, GitLab CI — no persistent disk between runs), the layer-5 in-process refresh from troubleshooting.md cannot persist rotated cookies. Run notebooklm auth refresh periodically on a workstation cron and push the refreshed file with gh secret set NOTEBOOKLM_AUTH_JSON < ~/.notebooklm/profiles/default/storage_state.json.
  3. On the server, run any non-login command:

    notebooklm list
    notebooklm auth check --test    # verifies the cookies still authenticate against Google
    

Why no extras: reduces the install surface to 4 deps (httpx, click, rich, filelock); avoids 200+ MB Chromium download in CI images.

For runtime configuration (env vars, profiles, parallel agents), see configuration.md#headless-servers--containers.

The cookie-copy recipe above ships a storage_state.json that eventually expires (cookies are short-lived; ephemeral CI runners can't persist rotations). The master-token path instead holds one durable Google master token and mints fresh web cookies from it on demand — no browser per session, and an expired session re-mints automatically (no manual re-login). One browser sign-in, then headless forever.

pip install "notebooklm-py[headless]"        # adds gpsoauth (pure-Python)

# One-time bootstrap (a visible browser opens Google's EmbeddedSetup; sign in
# with a DEDICATED/throwaway account, and the single-use oauth_token is captured
# automatically). Add [browser] for the auto-capture, or paste it with
# --oauth-token <value> on a headless box.
notebooklm login --master-token --account you@gmail.com

# Ship master_token.json to the server instead of storage_state.json:
scp ~/.notebooklm/profiles/default/master_token.json \
    user@server:~/.notebooklm/profiles/default/master_token.json

# On the server, just run commands — cookies are minted/refreshed as needed:
notebooklm list
# Force a re-mint by hand (or from cron) any time:
notebooklm login --master-token-refresh

When a master_token.json sits beside a profile's storage_state.json, an expired session is recovered by re-minting from the master token in-process (after the normal homepage/RotateCookies/headless ladder is exhausted) — so long-lived headless workers self-heal.

⚠️ Security: the master token is full-account, durable, and infostealer-grade — a materially larger blast radius than an expiring storage_state.json (it survives password changes until explicitly revoked). Use a dedicated/throwaway Google account only, store it 0600 (the CLI does), and never commit or log it. This path uses Google's Android auth flow (gpsoauth) and is unofficial/ToS-grey, like the rest of this client. See ADR-0023 for the design and rationale.

E. Contributor

Working on this repo.

Recommended (respects the checked-in uv.lock):

git clone https://github.com/teng-lin/notebooklm-py.git
cd notebooklm-py
uv sync --frozen --extra browser --extra dev --extra markdown
source .venv/bin/activate
uv run playwright install chromium
pre-commit install

Why uv sync --frozen and not uv pip install -e ".[all]": the repo has a checked-in uv.lock. uv sync --frozen enforces the lockfile and fails fast on drift; uv pip install ignores the lockfile and re-resolves transitively (will silently get newer versions of playwright, ruff, etc.).

Why three extras and not [all]: [all] is pip extras semantics. uv sync --extra X is the uv equivalent. The three extras here are the contributor subset of [all] = [browser, dev, markdown, mcp, server]. cookies is intentionally excluded (rookiepy build issues on Python 3.13+), and mcp / server are omitted from the default contributor flow because those adapters are not needed for the standard local suite; opt in via --extra cookies / --extra mcp / --extra server if needed.

Why browser is part of the contributor install: the default local test suite includes unit tests that import and patch playwright.sync_api, even though they do not launch a real browser. uv sync --frozen --extra dev installs pytest/ruff/mypy but not Playwright, so uv run pytest will fail with ModuleNotFoundError: No module named 'playwright'. Use the full contributor command above before running the default test suite.

Linux only: uv run playwright install-deps chromium (scoped form, matches test.yml).

Pre-commit checklist (run before every commit):

uv run ruff format --check . && \
    uv run ruff check . && \
    uv run mypy src/notebooklm --ignore-missing-imports && \
    uv run pytest --cov=src/notebooklm --cov-report=term-missing --cov-fail-under=90

Verify:

notebooklm --version
uv run pytest --cov=src/notebooklm --cov-report=term-missing --cov-fail-under=90
uv run pre-commit run --all-files

F. Power user

Non-default browsers, cookie extraction, markdown source dumps.

Why this section uses the combined [browser,cookies] form — unlike Persona A, which uses two separate pip install calls so a rookiepy build failure doesn't leave the user with nothing: power users explicitly opted in, know what rookiepy is, and prefer the all-or-nothing tradeoff (single command, no wrapping logic).

⚠️ Don't use [all] for power-user setups. [all] deliberately excludes cookies (see § All vs All-Extras). If you pip install "notebooklm-py[all]" and then try --browser-cookies, you'll get an opaque rookiepy import error. For everything-and-the-kitchen-sink, use pip install "notebooklm-py[browser,cookies,markdown]" explicitly (Python ≤ 3.12 only).

  • --browser-cookies (no Playwright login): pip install "notebooklm-py[browser,cookies]". Caveat: rookiepy may fail to install on Python 3.13/3.14; use Python 3.12 or accept the risk. See cli-reference.md#authentication-login for the full --browser-cookies syntax, including chrome::<profile-name-or-directory> for one Chromium user-profile and firefox::<container> for Firefox Multi-Account Containers (on every OS — not just macOS). Use notebooklm auth inspect --browser <browser> for previewing available accounts before import.
  • Markdown source dumps: pip install "notebooklm-py[markdown]" for notebooklm source fulltext -f markdown.
  • Edge instead of Chromium: install Microsoft Edge from microsoft.com/edge first — --browser msedge does NOT auto-install Edge (only --browser chromium auto-installs). Then notebooklm login --browser msedge.
  • Multi-account (personal + work): see configuration.md#multiple-accounts. Common power-user flow: notebooklm profile create work && notebooklm -p work login --browser-cookies edge --account work@corp.com. Use --all-accounts to bootstrap profiles for every signed-in Google account in one command.

Optional extras matrix

Source of truth: pyproject.toml [project.optional-dependencies].

Extra What it adds When you need it pip command uv (in your project)
(none) httpx, click, rich, filelock All RPC operations, all CLI commands except login. Suffices when you ship a storage_state.json. pip install notebooklm-py uv add notebooklm-py
browser playwright>=1.40.0 notebooklm login (interactive). pip install "notebooklm-py[browser]" uv add "notebooklm-py[browser]"
cookies rookiepy>=0.1.0 notebooklm login --browser-cookies <browser>, notebooklm auth inspect. pip install "notebooklm-py[cookies]" uv add "notebooklm-py[cookies]"
headless gpsoauth>=1.1.0 notebooklm login --master-token — headless auth that mints/refreshes web cookies from a durable master token, no per-session browser. Pure-Python (in all). See § D. pip install "notebooklm-py[headless]" uv add "notebooklm-py[headless]"
impersonate curl_cffi>=0.11 Experimental. Browser TLS/JA3 impersonation transport — set NOTEBOOKLM_TRANSPORT=curl_cffi to route the authenticated API surface through a Chrome-fingerprinted connection (insurance vs TLS fingerprint-gating); override the profile with NOTEBOOKLM_IMPERSONATE (default chrome, e.g. safari, chrome131). Native wheels. pip install "notebooklm-py[impersonate]" uv add "notebooklm-py[impersonate]"
markdown markdownify>=0.14.1 notebooklm source fulltext -f markdown. pip install "notebooklm-py[markdown]" uv add "notebooklm-py[markdown]"
mcp fastmcp>=2.14 Run the MCP server (notebooklm-mcp) so an MCP client/agent can drive NotebookLM as tools. pip install "notebooklm-py[mcp]" uv add "notebooklm-py[mcp]"
server fastapi, uvicorn[standard], python-multipart The localhost REST API server (notebooklm-server, experimental). See § REST API server. pip install "notebooklm-py[server]" uv add "notebooklm-py[server]"
dev pytest stack, mypy, ruff (==0.15.15 exact pin), pre-commit (>=4.5.1), vcrpy Contributor tooling only. Not sufficient for this repo's default uv run pytest; add browser too because some unit tests import Playwright. pip install "notebooklm-py[dev]" uv add "notebooklm-py[dev]" (in your project) — but contributors to this repo use the Persona E uv sync flow instead
all Resolves to browser + dev + headless + markdown + mcp + server (not cookies) Contributors who do not need rookiepy. pip install "notebooklm-py[all]" uv add "notebooklm-py[all]" (in your project) — see All vs All-Extras

Note on uv columns: the uv (in your project) column is for users adding notebooklm-py as a dependency in their own project (requires a pyproject.toml in that project). Contributors working inside this repo use the Persona E flow (uv sync --frozen --extra ...), governed by this repo's uv.lock. Do not run uv sync outside a project — it errors with No pyproject.toml found.


REST API server

⚠️ Experimental. Like the MCP adapter, the REST server is experimental: the /v1 surface and behavior may change in a minor release, and it is excluded from the public-API compatibility gate. Pin a version before relying on it for automation. The server also logs an experimental warning on every startup.

A single-tenant, localhost REST API over the same transport-neutral core as the CLI — the natural shape for scripting and agent automation (feed a notebook, generate an artifact, pull it down) without spawning a CLI process per call.

uv tool install "notebooklm-py[server]"    # fastapi + uvicorn + python-multipart
# OR, with pipx:  pipx install "notebooklm-py[server]"   (or plain pip inside a venv)

Prerequisite: a provisioned account (storage_state.json) from notebooklm login. The server holds one account for the process; it does not run browser login itself.

Launch:

export NOTEBOOKLM_SERVER_TOKEN="$(openssl rand -hex 32)"   # REQUIRED — the server refuses to start without it
notebooklm-server --host 127.0.0.1 --port 8000            # loopback-only by default

Configuration is read from NOTEBOOKLM_SERVER_* env vars (overridable by the matching flags):

Variable Default Purpose
NOTEBOOKLM_SERVER_TOKEN (unset) Bearer token every request must present. Required — fail-closed if unset.
NOTEBOOKLM_SERVER_HOST 127.0.0.1 Bind host. Non-loopback is refused unless the elevated-risk override below is set.
NOTEBOOKLM_SERVER_PORT 8000 Bind port.
NOTEBOOKLM_SERVER_ALLOW_EXTERNAL_BIND (unset) ⚠️ Set to 1 to bind a non-loopback interface. Only behind a trusted reverse proxy — this exposes account-fronting credentials to the network.
NOTEBOOKLM_SERVER_SOURCE_MUTATION_CONCURRENCY 4 Max concurrent source create/rename/delete/batch handlers.
NOTEBOOKLM_SERVER_SOURCE_WAIT_CONCURRENCY 4 Max concurrent source wait handlers.
NOTEBOOKLM_SERVER_GENERATION_CONCURRENCY 2 Max concurrent artifact generation/retry handlers.
NOTEBOOKLM_SERVER_DOWNLOAD_CONCURRENCY 2 Max concurrent artifact download handlers.
NOTEBOOKLM_SERVER_RESEARCH_CONCURRENCY 2 Max concurrent research start/cancel/import handlers.
NOTEBOOKLM_SERVER_CHAT_CONCURRENCY 4 Max concurrent blocking chat ask handlers.

The concurrency knobs are route-group backpressure for expensive work. They do not gate /healthz or cheap read/list/poll routes.

Surface: every route is under /v1 and requires Authorization: Bearer <token> plus a loopback Host header (a DNS-rebinding guard). /healthz is the one public, token-less route. The auto-generated /docs / /openapi.json schema UI is disabled (it would otherwise be reachable token-less).

TOKEN=$NOTEBOOKLM_SERVER_TOKEN
BASE=http://127.0.0.1:8000

curl $BASE/healthz                                                    # {"ok": true}  (no token)
curl -H "Authorization: Bearer $TOKEN" $BASE/v1/notebooks             # list notebooks
curl -H "Authorization: Bearer $TOKEN" -d '{"title":"My NB"}' \
     -H 'Content-Type: application/json' $BASE/v1/notebooks           # create
curl -H "Authorization: Bearer $TOKEN" -d '{"url":"https://example.com"}' \
     -H 'Content-Type: application/json' $BASE/v1/notebooks/<id>/sources/url
curl -H "Authorization: Bearer $TOKEN" -d '{"question":"Summarize"}' \
     -H 'Content-Type: application/json' $BASE/v1/notebooks/<id>/chat # blocking answer
curl -H "Authorization: Bearer $TOKEN" $BASE/v1/notebooks/<id>/share # sharing status

Endpoints: /v1/notebooks (list/get/create/delete); /v1/notebooks/{id}/sources (list/get/add via url·text·file/delete); /v1/notebooks/{id}/notes (list/get/create/update via PUT/delete); /v1/notebooks/{id}/chat (blocking ask, no streaming); /v1/notebooks/{id}/artifacts (list / generate / poll / download); /v1/notebooks/{id}/share (status / public link / users / view level). Long-running work (source ingest, artifact generation) is poll-the-resource: the create call returns immediately and the matching GET reports pending until the resource is ready (200), 404 for an id the server never created, 409/410 for a failed/removed artifact.

Artifacts & uploads:

# Generate (non-blocking → 202 + task_id). Omit source_ids to use ALL sources
# (like the CLI); pass them to scope. Some types (quiz/flashcards) need at least one source.
curl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
     -d '{"type":"quiz"}' $BASE/v1/notebooks/<id>/artifacts        # → {"task_id": ...}
curl -H "Authorization: Bearer $TOKEN" $BASE/v1/notebooks/<id>/artifacts/<task_id>  # poll
curl -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
     -d '{"type":"audio"}' $BASE/v1/notebooks/<id>/artifacts/download -o out.mp3     # download
# File upload is multipart (the original filename + content-type are preserved):
curl -H "Authorization: Bearer $TOKEN" -F 'file=@./notes.pdf' \
     $BASE/v1/notebooks/<id>/sources/file

Error envelope: every failure is {"error": {"category": "...", "message": "..."}} with a category-derived HTTP status — not_found→404, validation→400/422, auth→401/403, rate_limited→429, notebook_limit→409, server/network→502, timeouts→504. The category is classified once by _app.errors.classify, shared with the CLI.


Post-install steps

playwright install chromium — when required, when auto-installed

  • Required: when you'll use notebooklm login (the interactive Playwright flow), unless the CLI auto-installs Chromium for you (it does — see ensure_chromium_installed() in cli/services/playwright_login.py, which runs python -m playwright install chromium on first login if Chromium is missing).
  • Not required: for headless servers (Persona D), library use (Persona C), or --browser-cookies-based auth (Persona A/F with [cookies]).

playwright install-deps chromium — Linux system libraries

On Debian/Ubuntu, Playwright needs system libs for Chromium. Run after playwright install chromium:

playwright install-deps chromium       # scoped to chromium; matches CI

Works without sudo if you're root or have passwordless sudo. Otherwise sudo playwright install-deps chromium.

First-time notebooklm login

notebooklm login                       # opens Chromium for Google sign-in
notebooklm auth check --test           # verify

The login command:

  • Auto-installs Chromium if missing (Persona A/B/E).
  • Saves cookies to ~/.notebooklm/profiles/<profile>/storage_state.json.
  • Uses a persistent browser profile so subsequent logins are faster.

notebooklm skill install — for AI agents (Persona A)

Registers the skill into local agent skill directories:

notebooklm skill install               # writes ~/.claude/skills/notebooklm/, ~/.agents/skills/notebooklm/

Optional — only needed if your agent harness reads from those directories and the skill isn't already present.

Running the MCP server (mcp extra)

The MCP server ships behind the optional mcp extra (see the extras matrix above) and exposes the same _app/ business logic over the Model Context Protocol.

notebooklm-mcp                                         # installed console script (stdio transport)
uvx --from "notebooklm-py[mcp]" notebooklm-mcp         # no install — run straight from PyPI

Wire it into an MCP client with either:

  • notebooklm mcp install <client> — auto-writes the server config for claude-desktop, claude-code, cursor, or windsurf; or
  • the one-click .mcpb desktop bundle — download it from the latest release (Assets) and use Claude Desktop's "Install Extension". Each stable release attaches a prebuilt, version-matched bundle; see desktop-extension/README.md.

Full usage walkthrough (auth, transports, the 35 tools, workflows, troubleshooting): mcp-guide.md.


Verifying your install

Command What it checks Use when
notebooklm --version Package installed correctly. Always.
notebooklm auth check --json Auth file parses; SID cookie present. Returns {"status": "ok"|"error", "checks": {...}}. Agents (machine-parseable).
notebooklm auth check --test Same + network token-fetch validates that cookies still authenticate against Google. End users (after login).
notebooklm auth check --test --json Both. Agents that need to confirm the cookies aren't stale.
notebooklm list Package + auth + RPC roundtrip all work. After login, as a smoke test.

Important: notebooklm status reports context state (which notebook is selected). It is not an auth check. See Common gotchas.

Your first end-to-end run:

notebooklm create "My First Notebook"
notebooklm source add 'https://en.wikipedia.org/wiki/Python_(programming_language)'
notebooklm ask "Summarize the sources in three sentences"

For the full CLI surface, see cli-reference.md.


Platform notes

Platform Install-time notes Diagnostic detail
macOS Chromium auto-downloads on first login. --browser-cookies from Chrome/Edge/Brave/Opera may prompt for Keychain access. troubleshooting.md#macos
Linux (a) playwright install-deps chromium for system libs (Debian/Ubuntu). (b) Known bug: playwright > 1.57 may fail with TypeError: onExit is not a function — pin playwright==1.57.0. troubleshooting.md#linux
Windows The library auto-configures WindowsSelectorEventLoopPolicy and PYTHONUTF8=1. Prefer plain pip install (uv/pipx less common on Windows). troubleshooting.md#windows
WSL The browser opens in the Windows host (expected); storage_state.json lives in the WSL filesystem. troubleshooting.md#wsl

Upgrading and uninstalling

pip install --upgrade notebooklm-py            # latest patch
pip install --upgrade "notebooklm-py[browser]"  # preserves your extras

For pinning patterns and version-stability guarantees, see stability.md.

To uninstall:

pip uninstall notebooklm-py
rm -rf ~/.notebooklm                          # optional: remove auth state

Common gotchas (appendix)

All vs All-Extras

⚠️ pip install ".[all]" and uv sync --all-extras are not equivalent.

  • pyproject.toml defines: all = ["notebooklm-py[browser,dev,markdown,mcp,server]"] — a self-referential extras string that resolves to browser + dev + markdown + mcp + server only. It deliberately excludes cookies because rookiepy has install issues on Python 3.13+ (CHANGELOG [0.4.1]).
  • uv sync --all-extras installs every extra including cookies, and may fail on Python 3.13/3.14.
  • In this repo, prefer uv sync --frozen --extra browser --extra dev --extra markdown.

uv pip install vs uv sync

  • uv pip install -e ".[all]" ignores the checked-in uv.lock — it re-resolves dependencies and may pull newer versions of playwright, ruff, etc. than the lock specifies.
  • uv sync --frozen enforces the lockfile and fails fast on drift. This is what contributors should use.
  • uv sync (no --frozen) silently updates uv.lock if pyproject.toml has changed. Use only when intentionally bumping deps.

notebooklm status ≠ auth

notebooklm status reports the currently selected notebook (context). It does NOT report whether you are authenticated. For auth, use notebooklm auth check (or --json / --test --json for machine output and network validation).