# How to Add YouTube Videos as Sources Using the NotebookLM SourcesAPI

> Easily add YouTube videos as sources in NotebookLM using the SourcesAPI. This guide shows you how to use add_url to integrate video content seamlessly into your projects.

- Repository: [Teng Lin/notebooklm-py](https://github.com/teng-lin/notebooklm-py)
- Tags: how-to-guide
- Published: 2026-03-09

---

**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`](https://github.com/teng-lin/notebooklm-py/blob/main/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`](https://github.com/teng-lin/notebooklm-py/blob/main/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`](https://github.com/teng-lin/notebooklm-py/blob/main/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`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/_core.py).

The payload uses `RPCMethod.ADD_SOURCE` (defined in [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/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:

```python
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`:

```python
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`](https://github.com/teng-lin/notebooklm-py/blob/main/_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:

```python
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`](https://github.com/teng-lin/notebooklm-py/blob/main/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.