Opening
Imagine you’re building a research pipeline: you have 50 URLs to analyze, need audio summaries generated for each, and want everything exported to your local drive — every Monday morning, automatically. Doing this manually in the NotebookLM web UI would take hours of clicking. The web UI doesn’t even support batch downloads.
That’s the gap notebooklm-py fills. It’s an unofficial Python library (currently trending on GitHub with 9,000+ stars) that gives you full programmatic control over Google NotebookLM — including features the web interface doesn’t expose at all.
In this article, you’ll learn how to:
notebooklm-py⚠️ Heads up: This is an unofficial library using undocumented Google APIs. It’s best suited for personal projects, prototypes, and research pipelines — not production systems where Google API stability is critical.
Core Content
Installing and Authenticating
Install the package from PyPI:
pip install notebooklm-py
Authentication uses your Google session cookies. The library needs your __Secure-1PSID and __Secure-1PSIDTS cookies from a logged-in NotebookLM browser session.
from notebooklm import NotebookLM
# Authenticate using environment variables (recommended)
import os
client = NotebookLM(
cookie_1psid=os.environ["GOOGLE_1PSID"],
cookie_1psidts=os.environ["GOOGLE_1PSIDTS"],
)
# Verify connection by listing notebooks
notebooks = client.list_notebooks()
for nb in notebooks:
print(nb["id"], nb["title"])
# Output:
# abc123 My Research Notebook
# def456 Competitor Analysis
To get your cookies: open Chrome DevTools → Application → Cookies → notebooklm.google.com. Store them in environment variables, never hardcode them.
Creating Notebooks and Importing Sources
The real power starts when you automate notebook creation and bulk source importing.
from notebooklm import NotebookLM
import os
client = NotebookLM(
cookie_1psid=os.environ["GOOGLE_1PSID"],
cookie_1psidts=os.environ["GOOGLE_1PSIDTS"],
)
# Create a new notebook
notebook = client.create_notebook(title="Python Trends April 2026")
notebook_id = notebook["id"]
print(f"Created notebook: {notebook_id}")
# Output: Created notebook: nb_x9f2k1...
# Import multiple sources at once
urls: list[str] = [
"https://docs.python.org/3.13/whatsnew/3.13.html",
"https://peps.python.org/pep-0730/",
"https://github.com/astral-sh/uv/releases/tag/0.6.0",
]
for url in urls:
result = client.add_source(notebook_id=notebook_id, url=url)
print(f"Added source: {result['title']}")
# Output:
# Added source: What's New In Python 3.13
# Added source: PEP 730 – CPython on iOS
# Added source: uv 0.6.0 release notes
You can also import PDFs, YouTube videos, Google Drive files, and plain text. The add_source method accepts a file_path parameter for local files:
# Import a local PDF
import pathlib
pdf_path = pathlib.Path("research/paper.pdf")
result = client.add_source(
notebook_id=notebook_id,
file_path=str(pdf_path),
display_name="Research Paper Q1 2026",
)
print(f"Imported: {result['title']}, ID: {result['id']}")
# Output: Imported: Research Paper Q1 2026, ID: src_4k2m9...
Generating Audio Overviews Programmatically
This is where notebooklm-py really shines over the web UI — you can trigger Audio Overview generation in batch and download the results automatically.
from notebooklm import NotebookLM, AudioFormat, AudioLength
import os
import time
client = NotebookLM(
cookie_1psid=os.environ["GOOGLE_1PSID"],
cookie_1psidts=os.environ["GOOGLE_1PSIDTS"],
)
notebook_id = "nb_x9f2k1..." # from previous step
# Request a deep-dive audio overview in English
job = client.generate_audio_overview(
notebook_id=notebook_id,
format=AudioFormat.DEEP_DIVE,
length=AudioLength.MEDIUM,
language="en",
)
print(f"Audio job started: {job['job_id']}, status: {job['status']}")
# Output: Audio job started: job_8h3p2..., status: pending
# Poll for completion (usually 30-90 seconds)
while True:
status = client.get_audio_status(notebook_id=notebook_id)
if status["state"] == "complete":
print("Audio ready!")
break
elif status["state"] == "failed":
raise RuntimeError("Audio generation failed")
print(f"Status: {status['state']}, waiting 10s...")
time.sleep(10)
# Download the MP3
output_path = client.download_audio(
notebook_id=notebook_id,
destination="./outputs/overview.mp3",
)
print(f"Downloaded to: {output_path}")
# Output: Downloaded to: ./outputs/overview.mp3
Available audio formats: DEEP_DIVE, BRIEF, CRITIQUE, DEBATE. Lengths: SHORT, MEDIUM, LONG. Over 50 languages are supported — including Malay, Indonesian, and Thai.
Triggering Research Agents and Extracting Results
Beyond storing sources you manually provide, NotebookLM has a research agent that can search the web and auto-import relevant content. notebooklm-py exposes this programmatically:
from notebooklm import NotebookLM, ResearchMode
import os
client = NotebookLM(
cookie_1psid=os.environ["GOOGLE_1PSID"],
cookie_1psidts=os.environ["GOOGLE_1PSIDTS"],
)
notebook_id = "nb_x9f2k1..."
# Run a web research query — auto-imports found sources
research_result = client.run_research(
notebook_id=notebook_id,
query="Python async patterns best practices 2026",
mode=ResearchMode.DEEP, # or ResearchMode.FAST
auto_import=True,
)
print(f"Research complete. Imported {len(research_result['imported_sources'])} sources:")
for src in research_result["imported_sources"]:
print(f" - {src['title']} ({src['url']})")
# Output:
# Research complete. Imported 4 sources:
# - Python AsyncIO Deep Dive 2026 (https://realpython.com/...)
# - Async patterns in production (https://blog....)
# - ...
After research, you can chat with the notebook programmatically:
response = client.chat(
notebook_id=notebook_id,
message="What are the 3 most important async patterns across my sources?",
)
print(response["answer"])
# Output: Based on your sources, the three most important patterns are:
# 1. TaskGroup for structured concurrency...
Common Mistakes
Mistake 1: Storing Cookies as Code Constants
Wrong:
# NEVER do this — cookies expire and you'll expose credentials in source control
client = NotebookLM(
cookie_1psid="APA91b...", # hardcoded secret
cookie_1psidts="sidts_abc123", # hardcoded secret
)
Right:
import os
from dotenv import load_dotenv
load_dotenv() # loads from .env file (add .env to .gitignore!)
client = NotebookLM(
cookie_1psid=os.environ["GOOGLE_1PSID"],
cookie_1psidts=os.environ["GOOGLE_1PSIDTS"],
)
Why it matters: Google session cookies expire in days to weeks. Hardcoding them means your script breaks silently and, worse, commits them to version control where they might be exposed before expiry.
Mistake 2: Not Handling API Instability
Since notebooklm-py uses undocumented Google APIs, they can break without warning. Treating it like a stable SDK will cause painful production outages.
Wrong:
# No error handling — fails silently or crashes entire pipeline
notebook = client.create_notebook(title="Weekly Research")
client.add_source(notebook_id=notebook["id"], url=some_url)
audio = client.generate_audio_overview(notebook_id=notebook["id"])
Right:
import logging
from notebooklm.exceptions import NotebookLMAPIError, RateLimitError
logger = logging.getLogger(__name__)
def safe_create_pipeline(client: NotebookLM, title: str, url: str) -> dict | None:
try:
notebook = client.create_notebook(title=title)
client.add_source(notebook_id=notebook["id"], url=url)
return notebook
except RateLimitError:
logger.warning("Rate limit hit — waiting 60 seconds")
time.sleep(60)
return None
except NotebookLMAPIError as e:
logger.error(f"NotebookLM API error: {e}. Google may have changed endpoints.")
return None
Why it matters: defensive error handling keeps your pipeline running and gives you actionable logs when Google inevitably tweaks something.
Wrap-up
notebooklm-py unlocks a powerful workflow that the NotebookLM web UI simply can’t offer: batch source imports, programmatic audio generation, automated research agents, and local file exports — all from Python scripts or AI agents.
The key steps: install via pip, authenticate with browser cookies stored as environment variables, create notebooks, import sources (URLs, PDFs, YouTube), and trigger content generation. Use proper error handling given the unofficial API nature.
The logical next step: combine this with a task scheduler like APScheduler or a simple cron job to build a fully automated weekly research digest — your NotebookLM notebooks populated and audio summaries downloaded every Monday morning, zero manual effort.
No comments yet. Be the first to leave a comment!