How to Add YouTube Videos as Sources Using the NotebookLM SourcesAPI

Call await client.sources.add_url(notebook_id, youtube_url) to add YouTube videos to a NotebookLM notebook; the SourcesAPI automatically detects YouTube URLs, extracts video IDs, and manages the underlying RPC communication.

The notebooklm-py library by teng-lin provides a high-level SourcesAPI that abstracts Google NotebookLM's complex RPC layer into simple async methods. When adding YouTube videos, the library handles URL validation, video ID extraction, and asynchronous processing polling automatically.

How the SourcesAPI Handles YouTube URLs

The addition flow relies on three internal components working sequentially. In src/notebooklm/_sources.py, the public add_url method delegates to specialized helpers when it detects a YouTube domain.

Automatic YouTube Detection and ID Extraction

Before sending any network requests, add_url calls _extract_youtube_video_id (defined at lines 775–795 in src/notebooklm/_sources.py). This helper parses the URL structure, validates the hostname against known YouTube domains, and extracts the video identifier.

The helper recognizes multiple YouTube URL formats:

  • Standard watch URLs: https://www.youtube.com/watch?v=VIDEO_ID
  • Short URLs: https://youtu.be/VIDEO_ID
  • Shorts: https://youtube.com/shorts/VIDEO_ID
  • Embed links: https://youtube.com/embed/VIDEO_ID
  • Live streams and mobile variants

If extraction succeeds, control passes to _add_youtube_source; otherwise, the method falls back to generic URL handling.

YouTube-Specific RPC Payload Construction

The _add_youtube_source method (lines 868–879 in src/notebooklm/_sources.py) constructs the exact RPC payload required by NotebookLM's internal API. It formats the video URL into a nested parameter structure with type code indicators and sends it via ClientCore.rpc_call from src/notebooklm/_core.py.

The payload uses RPCMethod.ADD_SOURCE (defined in src/notebooklm/rpc/types.py) and targets the /notebook/{notebook_id} endpoint. This mirrors the batch execute calls made by the official NotebookLM web interface.

Adding YouTube Videos to Your Notebook

Basic Fire-and-Forget Addition

For simple use cases where you don't need immediate processing confirmation, call add_url with just the notebook ID and URL:

from notebooklm import NotebookLMClient

async def add_video():
    async with await NotebookLMClient.from_storage() as client:
        notebook_id = "nb_12345"
        url = "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
        
        source = await client.sources.add_url(notebook_id, url)
        print(f"Added source {source.id} with status {source.status}")

This returns immediately with a Source object, though the underlying video may still be processing.

Waiting for Processing Completion

To block until the video is fully processed and ready for chat or artifact generation, set wait=True and optionally adjust wait_timeout:

async def add_and_wait():
    async with await NotebookLMClient.from_storage() as client:
        source = await client.sources.add_url(
            notebook_id="nb_12345",
            url="https://youtu.be/dQw4w9WgXcQ",
            wait=True,
            wait_timeout=180.0
        )
        print(f"Source ready: {source.title}")

When waiting, the library polls using wait_until_ready (implementing exponential back-off at lines 176–224 in _sources.py) and raises SourceTimeoutError or SourceProcessingError on failure.

Direct Low-Level Access (Advanced)

For debugging or custom batching scenarios, bypass the automatic detection by calling the private helper directly:

async def manual_add():
    async with await NotebookLMClient.from_storage() as client:
        raw_response = await client.sources._add_youtube_source(
            "nb_12345", 
            "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
        )
        source = client.types.Source.from_api_response(raw_response)

This skips the URL validation layer and sends the RPC immediately.

Summary

  • The SourcesAPI in teng-lin/notebooklm-py provides the add_url method in src/notebooklm/_sources.py for high-level YouTube addition.
  • Automatic detection via _extract_youtube_video_id (lines 775–795) handles standard, short, shorts, and embed URL formats.
  • The RPC payload built by _add_youtube_source (lines 868–879) communicates with NotebookLM's internal batch execute endpoint through ClientCore.
  • Set wait=True to poll until the source reaches READY status using exponential back-off logic.
  • All YouTube-specific parameters are encapsulated; callers only need to provide the notebook ID and video URL.

Frequently Asked Questions

What YouTube URL formats does the SourcesAPI support?

The _extract_youtube_video_id helper supports standard watch URLs (youtube.com/watch?v=), short links (youtu.be/), Shorts (/shorts/), embed paths (/embed/), and various mobile/live stream variants. As long as the URL contains a valid 11-character video ID and uses a recognized YouTube domain, the library extracts it correctly.

How can I verify when a YouTube source finishes processing?

Pass wait=True to add_url to block until processing completes. The method uses wait_until_ready with exponential back-off polling. Alternatively, call add_url without waiting and later check source.status manually or call client.sources.get() to retrieve the current state.

Does the same method work for non-YouTube URLs?

Yes. If _extract_youtube_video_id returns None, add_url automatically falls back to _add_url_source, which handles generic web pages, PDFs, and other document types. The public interface remains identical regardless of source type.

What happens if I provide an invalid or private YouTube video?

If the URL format is invalid, the method falls back to generic URL handling, which may fail at the server level. For valid-format but private/deleted videos, the RPC call succeeds but the source status will indicate an error. When using wait=True, the library raises SourceProcessingError if the server reports a processing failure.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →