Try Live
Add Docs
Rankings
Pricing
Docs
Install
Install
Docs
Pricing
More...
More...
Try Live
Rankings
Enterprise
Create API Key
Add Docs
NotebookLM SDK
https://github.com/agmmnn/notebooklm-sdk
Admin
NotebookLM SDK is a TypeScript SDK that enables programmatic automation of Google NotebookLM,
...
Tokens:
9,155
Snippets:
88
Trust Score:
9.7
Update:
2 weeks ago
Context
Skills
Chat
Benchmark
96.5
Suggestions
Latest
Show doc for...
Code
Info
Show Results
Context Summary (auto-generated)
Raw
Copy
Link
# NotebookLM SDK NotebookLM SDK is an unofficial TypeScript SDK that enables programmatic automation of Google NotebookLM. It provides a complete API for creating notebooks, managing sources (URLs, files, text, Google Drive), generating AI artifacts (podcasts, videos, reports, slide decks, quizzes, flashcards), chatting with documents, and running web research—all from Node.js, Bun, or Deno. The SDK reverse-engineers NotebookLM's internal API and provides auto-discovery of authentication tokens, automatic session refresh on auth failures, and a comprehensive error handling system. It supports all major NotebookLM features including AI-generated podcasts (Audio Overview), video overviews, reports, slide decks, infographics, mind maps, quizzes, flashcards, and data tables. ## Installation and Setup ```bash npm install notebooklm-sdk # or bun add notebooklm-sdk ``` ## Authentication The SDK supports multiple authentication methods. Run the login command once to authenticate with your Google account, and the session is automatically discovered on subsequent connections. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; // Zero-config — auto-discovers session from ~/.notebooklm/session.json const client = await NotebookLMClient.connect(); // Or explicit cookie string (for CI/server environments) const client = await NotebookLMClient.connect({ cookies: process.env.NOTEBOOKLM_COOKIES, // "SID=...; HSID=..." }); // Or explicit file path to Playwright storage state const client = await NotebookLMClient.connect({ cookiesFile: "./session.json", }); // With custom timeout const client = await NotebookLMClient.connect({}, { timeoutMs: 60000 }); ``` ```bash # Interactive login (opens Chrome for Google sign-in) npx notebooklm-sdk login # Verify session is valid npx notebooklm-sdk whoami ``` ## Notebooks API Manage notebooks programmatically—create, rename, delete, list, and get summaries. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); // List all notebooks const notebooks = await client.notebooks.list(); console.log("Notebooks:", notebooks.map((nb) => nb.title)); // Create a new notebook const { id } = await client.notebooks.create("My Research"); console.log(`Created notebook: ${id}`); // Rename notebook await client.notebooks.rename(id, "My Updated Research"); // Get notebook details const nb = await client.notebooks.get(id); console.log(`Title: ${nb.title}, Sources: ${nb.sourcesCount}`); // Get AI-generated summary const summary = await client.notebooks.getSummary(id); console.log(`Summary: ${summary}`); // Get structured description with suggested topics const desc = await client.notebooks.getDescription(id); console.log(`Topics: ${desc.suggestedTopics.join(", ")}`); // Get metadata with simplified source list const metadata = await client.notebooks.getMetadata(id); console.log(`Sources: ${metadata.sources.length}`); // Remove from recent (doesn't delete) await client.notebooks.removeFromRecent(id); // Delete notebook await client.notebooks.delete(id); ``` ## Sources API Add various source types (URLs, text, files, Google Drive) and wait for processing. ```typescript import { NotebookLMClient, DriveMimeType } from "notebooklm-sdk"; import * as fs from "node:fs/promises"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Add URL source (webpage or YouTube video) const urlSource = await client.sources.addUrl( notebookId, "https://en.wikipedia.org/wiki/TypeScript" ); // Add text source const textSource = await client.sources.addText( notebookId, "The mitochondria is the powerhouse of the cell.", "Biology Fact" ); // Add file from disk const fileSource = await client.sources.addFile( notebookId, "./document.pdf", "application/pdf" ); // Add file from buffer const buffer = await fs.readFile("report.md"); const bufferSource = await client.sources.addFileBuffer( notebookId, buffer, "report.md", "text/markdown" ); // Add Google Drive file const driveSource = await client.sources.addDrive( notebookId, "1abc123xyz", // Drive file ID "My Google Doc", DriveMimeType.GOOGLE_DOC ); // Wait for source to finish processing await client.sources.waitUntilReady(notebookId, urlSource.id); // Wait for multiple sources in parallel await client.sources.waitForSources(notebookId, [ textSource.id, fileSource.id, ]); // List all sources const sources = await client.sources.list(notebookId); console.log("Sources:", sources.map((s) => s.title)); // Get full indexed text content const fulltext = await client.sources.getFulltext(notebookId, urlSource.id); console.log(`${fulltext.charCount} chars indexed`); // Get AI-generated source guide (summary + keywords) const guide = await client.sources.getGuide(notebookId, urlSource.id); console.log(`Summary: ${guide.summary}`); console.log(`Keywords: ${guide.keywords.join(", ")}`); // Check if URL source has newer content const isFresh = await client.sources.checkFreshness(notebookId, urlSource.id); if (!isFresh) { await client.sources.refresh(notebookId, urlSource.id); } // Rename source await client.sources.rename(notebookId, urlSource.id, "New Title"); // Delete source await client.sources.delete(notebookId, urlSource.id); ``` ## Artifacts API - Audio and Video Generate AI podcasts (Audio Overview) and video overviews from notebook sources. ```typescript import * as fs from "node:fs/promises"; import { NotebookLMClient, AudioFormat, AudioLength, VideoFormat, VideoStyle, } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Generate audio podcast const { artifactId } = await client.artifacts.createAudio(notebookId, { format: AudioFormat.DEEP_DIVE, // or CONCISE_OVERVIEW, DEBATE, CUSTOM length: AudioLength.DEFAULT, // or SHORT, LONG language: "en", }); console.log(`Generating podcast... (${artifactId})`); // Wait for completion (up to 10 minutes, poll every 5 seconds) const audioArtifact = await client.artifacts.waitUntilReady( notebookId, artifactId!, 600, 5 ); // Download MP3 const mp3 = await client.artifacts.downloadAudio(notebookId, audioArtifact.id); await fs.mkdir("downloads", { recursive: true }); await fs.writeFile(`downloads/${audioArtifact.id}.mp3`, mp3); console.log(`Saved MP3 (${(mp3.length / 1024 / 1024).toFixed(2)} MB)`); // Generate video overview const videoGen = await client.artifacts.createVideo(notebookId, { format: VideoFormat.CINEMATIC, style: VideoStyle.CLASSIC, }); const videoArtifact = await client.artifacts.waitUntilReady( notebookId, videoGen.artifactId! ); const mp4 = await client.artifacts.downloadVideo(notebookId, videoArtifact.id); await fs.writeFile(`downloads/${videoArtifact.id}.mp4`, mp4); ``` ## Artifacts API - Reports and Documents Generate briefing docs, study guides, blog posts, and custom reports. ```typescript import * as fs from "node:fs/promises"; import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Get AI-suggested report formats const suggestions = await client.artifacts.suggestReports(notebookId); for (const s of suggestions) { console.log(`${s.title}: ${s.description}`); } // Generate briefing doc const { artifactId } = await client.artifacts.createReport(notebookId, { format: "briefing_doc", // or "study_guide", "blog_post", "custom" language: "en", }); // For custom format, provide a prompt const custom = await client.artifacts.createReport(notebookId, { format: "custom", customPrompt: "Create a technical whitepaper with code examples", }); const artifact = await client.artifacts.waitUntilReady(notebookId, artifactId!); // Get markdown content const markdown = await client.artifacts.getReportMarkdown( notebookId, artifact.id ); await fs.writeFile(`downloads/${artifact.id}.md`, markdown!); // Export to Google Docs const docUrl = await client.artifacts.exportReport( notebookId, artifact.id, "My Report Title" ); console.log(`Google Doc: ${docUrl}`); ``` ## Artifacts API - Slide Decks and Infographics Generate presentation slide decks and infographic images. ```typescript import * as fs from "node:fs/promises"; import { NotebookLMClient, SlideDeckFormat, SlideDeckLength, InfographicOrientation, InfographicDetail, InfographicStyle, } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Generate slide deck const { artifactId } = await client.artifacts.createSlideDeck(notebookId, { format: SlideDeckFormat.DETAILED_DECK, length: SlideDeckLength.DEFAULT, }); await client.artifacts.waitUntilReady(notebookId, artifactId!); // Download as PDF const pdf = await client.artifacts.downloadSlideDeck( notebookId, artifactId!, "pdf" ); await fs.writeFile(`downloads/${artifactId}.pdf`, pdf); // Download as PowerPoint const pptx = await client.artifacts.downloadSlideDeck( notebookId, artifactId!, "pptx" ); await fs.writeFile(`downloads/${artifactId}.pptx`, pptx); // Revise a specific slide (zero-based index) await client.artifacts.reviseSlide( notebookId, artifactId!, 0, // slide index "Move the title to the top and add bullet points" ); // Generate infographic const infographic = await client.artifacts.createInfographic(notebookId, { orientation: InfographicOrientation.LANDSCAPE, detail: InfographicDetail.STANDARD, style: InfographicStyle.PROFESSIONAL, }); await client.artifacts.waitUntilReady(notebookId, infographic.artifactId!); const png = await client.artifacts.downloadInfographic( notebookId, infographic.artifactId! ); await fs.writeFile(`downloads/infographic.png`, png); ``` ## Artifacts API - Quizzes, Flashcards, Data Tables, and Mind Maps Generate interactive learning materials and structured data outputs. ```typescript import * as fs from "node:fs/promises"; import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Generate quiz const quiz = await client.artifacts.createQuiz(notebookId); await client.artifacts.waitUntilReady(notebookId, quiz.artifactId!); const quizHtml = await client.artifacts.getInteractiveHtml( notebookId, quiz.artifactId! ); await fs.writeFile("downloads/quiz.html", quizHtml!); // Generate flashcards const flashcards = await client.artifacts.createFlashcards(notebookId); await client.artifacts.waitUntilReady(notebookId, flashcards.artifactId!); const flashcardsHtml = await client.artifacts.getInteractiveHtml( notebookId, flashcards.artifactId! ); await fs.writeFile("downloads/flashcards.html", flashcardsHtml!); // Generate data table const table = await client.artifacts.createDataTable(notebookId); await client.artifacts.waitUntilReady(notebookId, table.artifactId!); const tableContent = await client.artifacts.getDataTableContent( notebookId, table.artifactId! ); // { headers: string[], rows: string[][] } const csv = [tableContent!.headers, ...tableContent!.rows] .map((r) => r.join(",")) .join("\n"); await fs.writeFile("downloads/data.csv", csv); // Export data table to Google Sheets const sheetUrl = await client.artifacts.exportDataTable( notebookId, table.artifactId!, "My Data Table" ); console.log(`Google Sheet: ${sheetUrl}`); // Generate mind map (synchronous - returns immediately) const mindMap = await client.artifacts.createMindMap(notebookId); const mindMapJson = JSON.parse(mindMap.content); await fs.writeFile("downloads/mindmap.json", JSON.stringify(mindMapJson, null, 2)); // List existing mind maps const mindMaps = await client.notes.listMindMaps(notebookId); ``` ## Artifacts API - Listing and Status List all artifacts and check generation status. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // List all artifacts const artifacts = await client.artifacts.list(notebookId); for (const a of artifacts) { console.log(`[${a.kind}] ${a.status} - ${a.title ?? a.id}`); } // Filtered list helpers const audio = await client.artifacts.listAudio(notebookId); const video = await client.artifacts.listVideo(notebookId); const reports = await client.artifacts.listReports(notebookId); const quizzes = await client.artifacts.listQuizzes(notebookId); const flashcards = await client.artifacts.listFlashcards(notebookId); const infographics = await client.artifacts.listInfographics(notebookId); const slideDecks = await client.artifacts.listSlideDecks(notebookId); const dataTables = await client.artifacts.listDataTables(notebookId); // Check status without waiting const status = await client.artifacts.pollStatus(notebookId, "artifact-id"); console.log(`Status: ${status.status}`); // "pending", "in_progress", "completed", "failed" ``` ## Chat API Ask questions about notebook sources and maintain conversation context. ```typescript import { NotebookLMClient, ChatMode, ChatGoal, ChatResponseLength } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Set chat mode (persists on server) await client.chat.setMode(notebookId, ChatMode.CONCISE); // Options: DEFAULT, CONCISE, DETAILED, LEARNING_GUIDE // Or use configure() for fine-grained control await client.chat.configure( notebookId, ChatGoal.CUSTOM, ChatResponseLength.DEFAULT, "You are a concise summarizer. Always respond in bullet points." ); // Ask a question const result = await client.chat.ask( notebookId, "What is this notebook about? Give a 1-sentence summary." ); console.log(`Answer: ${result.answer}`); console.log(`References: ${result.references.length}`); console.log(`Conversation ID: ${result.conversationId}`); // Follow-up in the same conversation const followUp = await client.chat.ask( notebookId, "What's the main topic in one word?", { conversationId: result.conversationId } ); console.log(`Follow-up: ${followUp.answer}`); // Get conversation history const turns = await client.chat.getConversationTurns( notebookId, result.conversationId ); for (const turn of turns) { console.log(`Q: ${turn.query}`); console.log(`A: ${turn.answer}\n`); } // Get last conversation ID const lastConvId = await client.chat.getLastConversationId(notebookId); // Get history as [question, answer] pairs const history = await client.chat.getHistory(notebookId, 50); // Get locally cached turns const cached = client.chat.getCachedTurns(result.conversationId); ``` ## Research API Run web research and import results as notebook sources. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Start web research await client.research.start( notebookId, "Latest AI models 2024", "web", // or "drive" "fast" // or "deep" ); console.log("Researching..."); // Poll until complete let result = await client.research.poll(notebookId); while (result.status === "in_progress") { await new Promise((r) => setTimeout(r, 3000)); result = await client.research.poll(notebookId); } console.log(`Found ${result.sources.length} sources`); console.log(`Summary: ${result.summary}`); // Display found sources for (const src of result.sources) { console.log(`- ${src.title}: ${src.url}`); } // Import selected sources into notebook const imported = await client.research.importSources( notebookId, result.taskId!, result.sources.slice(0, 5) // Import top 5 results ); console.log(`Imported ${imported.length} sources`); ``` ## Notes API Create and manage user notes (distinct from AI-generated artifacts). ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Create a note const note = await client.notes.create( notebookId, "# My Research Notes\n\nKey findings from the sources...", "Research Notes" ); console.log(`Created note: ${note.id}`); // Update note content await client.notes.update( notebookId, note.id, "# Updated Notes\n\nRevised findings...", "Updated Research Notes" ); // Get a specific note const retrieved = await client.notes.get(notebookId, note.id); console.log(`Title: ${retrieved.title}`); console.log(`Content: ${retrieved.content}`); // List all text notes (excludes mind maps) const notes = await client.notes.list(notebookId); for (const n of notes) { console.log(`[${n.id}] ${n.title ?? "(untitled)"}`); } // List mind maps (stored as notes internally) const mindMaps = await client.notes.listMindMaps(notebookId); for (const mm of mindMaps) { const json = JSON.parse(mm.content); console.log(`Mind map: ${mm.title}`); } // Delete note await client.notes.delete(notebookId, note.id); // Delete mind map await client.notes.deleteMindMap(notebookId, "mindmap-id"); ``` ## Sharing API Control public access and per-user permissions for notebooks. ```typescript import { NotebookLMClient, SharePermission } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); const notebookId = "your-notebook-id"; // Get current sharing status const status = await client.sharing.getStatus(notebookId); console.log(`Public: ${status.isPublic}`); console.log(`Share URL: ${status.shareUrl}`); console.log(`Shared with: ${status.sharedUsers.length} users`); // Enable/disable public access await client.sharing.setPublic(notebookId, true); // Add user with viewer permission await client.sharing.addUser( notebookId, "viewer@example.com", SharePermission.VIEWER ); // Add user with editor permission await client.sharing.addUser( notebookId, "editor@example.com", SharePermission.EDITOR ); // Update user permission await client.sharing.updateUser( notebookId, "viewer@example.com", SharePermission.EDITOR ); // Remove user await client.sharing.removeUser(notebookId, "editor@example.com"); // Get share URL for notebook or specific artifact const url = client.notebooks.getShareUrl(notebookId); const artifactUrl = client.notebooks.getShareUrl(notebookId, "artifact-id"); ``` ## Settings API Get and set output language for AI-generated content. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); // Get current output language const lang = await client.settings.getOutputLanguage(); console.log(`Current language: ${lang}`); // "en", "ja", "fr", etc. // Set output language await client.settings.setOutputLanguage("ja"); // Japanese await client.settings.setOutputLanguage("fr"); // French await client.settings.setOutputLanguage("en"); // English ``` ## Error Handling All errors extend `NotebookLMError` with specific error types for different failure modes. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; import { NotebookLMError, AuthError, ArtifactNotReadyError, SourceTimeoutError, SourceProcessingError, RateLimitError, NotebookNotFoundError, } from "notebooklm-sdk/errors"; const client = await NotebookLMClient.connect(); try { const artifact = await client.artifacts.downloadAudio(notebookId, artifactId); } catch (err) { if (err instanceof AuthError) { // Session expired — re-authenticate console.error("Session expired. Run: npx notebooklm-sdk login"); } else if (err instanceof ArtifactNotReadyError) { // Artifact still generating — wait and retry console.log("Artifact not ready, waiting..."); await client.artifacts.waitUntilReady(notebookId, artifactId); } else if (err instanceof SourceTimeoutError) { // Source processing timed out console.error("Source processing timed out"); } else if (err instanceof SourceProcessingError) { // Source failed to process console.error("Source processing failed"); } else if (err instanceof RateLimitError) { // Too many requests — retry after delay console.log(`Rate limited. Retry after: ${err.retryAfter}ms`); } else if (err instanceof NotebookNotFoundError) { console.error("Notebook not found"); } else if (err instanceof NotebookLMError) { // Generic SDK error console.error(`SDK error: ${err.message}`); } } ``` ## Full Lifecycle Example Complete example showing notebook creation, source management, chat, and cleanup. ```typescript import { NotebookLMClient } from "notebooklm-sdk"; const client = await NotebookLMClient.connect(); // Create notebook const { id } = await client.notebooks.create("Temp Notebook"); await client.notebooks.rename(id, "My Test Notebook"); console.log(`Created: ${id}`); // Add multiple source types const textSource = await client.sources.addText( id, "The mitochondria is the powerhouse of the cell.", "Biology Fact" ); const urlSource = await client.sources.addUrl( id, "https://en.wikipedia.org/wiki/NotebookLM" ); const fileSource = await client.sources.addFileBuffer( id, Buffer.from("# Hello\n\nThis is a test file."), "test.md", "text/markdown" ); // Wait for all sources to be processed await Promise.all([ client.sources.waitUntilReady(id, textSource.id), client.sources.waitUntilReady(id, urlSource.id), client.sources.waitUntilReady(id, fileSource.id), ]); console.log("All sources ready"); // Chat with sources const { answer } = await client.chat.ask( id, "Summarize all sources in one sentence each." ); console.log(`Answer: ${answer}`); // Generate podcast const { artifactId } = await client.artifacts.createAudio(id, { format: "deep_dive", }); const audio = await client.artifacts.waitUntilReady(id, artifactId!); const mp3 = await client.artifacts.downloadAudio(id, audio.id); console.log(`Podcast: ${mp3.length} bytes`); // Clean up await client.notebooks.delete(id); console.log("Notebook deleted"); ``` ## TypeScript Types Key types exported from the SDK for type-safe development. ```typescript import type { Notebook, Source, Artifact, ArtifactStatus, ArtifactType, Note, ShareStatus, SharedUser, AskResult, ChatReference, ConversationTurn, SourceFulltext, SourceGuide, DataTableContent, ReportSuggestion, } from "notebooklm-sdk"; // Notebook: { id, title, createdAt, sourcesCount, isOwner } // Source: { id, title, url, kind, status, createdAt } // Artifact: { id, title, kind, status, notebookId, audioUrl, videoUrl, content } // AskResult: { answer, conversationId, turnNumber, references } // ShareStatus: { isPublic, access, viewLevel, sharedUsers, shareUrl } // DataTableContent: { headers: string[], rows: string[][] } ``` ## Summary NotebookLM SDK enables developers to build powerful document-centric applications by programmatically controlling Google NotebookLM. Common use cases include content pipelines that automatically generate podcasts or reports from ingested articles, research automation workflows that import web findings and query them via chat, document Q&A bots built on top of the chat API, and batch artifact generation for creating educational materials like quizzes and flashcards from source libraries. The SDK follows a consistent pattern across all APIs: connect once with auto-discovered authentication, perform operations on notebooks and their sources, and poll async artifacts until completion. Integration typically involves creating a notebook, adding sources (waiting for processing), generating artifacts or chatting with the content, and optionally sharing results. The comprehensive error hierarchy enables robust production applications with proper handling for authentication failures, rate limits, and processing errors.