# Risk Factors When Using Undocumented Google RPC APIs: A Technical Analysis of notebooklm-py

> Explore the risks of using undocumented Google RPC APIs like method-ID volatility and authentication churn with notebooklm-py. Understand the technical challenges and avoid sanctions.

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

---

**Using undocumented Google RPC APIs exposes applications to method-ID volatility, authentication churn, and account sanctions because these internal endpoints lack versioning, stability guarantees, or official deprecation notices.**

The **notebooklm-py** repository by teng-lin demonstrates exactly how precarious these integrations can be. The client communicates with Google’s NotebookLM service through reverse-engineered `batchexecute` RPC methods defined in [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/rpc/types.py), bypassing any official API surface. Understanding the specific risk factors when using undocumented Google RPC APIs is essential before deploying such code in production environments.

## Method-ID Volatility and Breaking Changes

The most immediate threat stems from **method-ID volatility**. Google’s internal RPC system uses obfuscated integer identifiers to route requests to specific handlers. In [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/rpc/types.py), the `RPCMethod` enum catalogs these reverse-engineered IDs with an explicit warning: “Reverse-engineered from network traffic analysis”【/src/notebooklm/rpc/types.py†L11-L21】.

When Google modifies its internal routing table—something that can happen without warning—these IDs shift. A call that previously succeeded returns **HTTP 404** or malformed payloads. Because the wrapper methods in `_notebooks.py::list()` or `_sources.py::add_url()` hardcode these IDs, every dependent function fails simultaneously. Unlike public APIs with deprecation headers and migration guides, these changes offer zero notice.

## Parameter-Nesting Fragility in batchexecute Payloads

Undocumented RPCs rely on **highly specific parameter nesting** that mirrors internal UI state rather than stable data contracts. The `batchexecute` endpoint expects payloads with nesting levels ranging from single to quadruple brackets depending on the operation.

According to [`docs/rpc-reference.md`](https://github.com/teng-lin/notebooklm-py/blob/main/docs/rpc-reference.md), deleting a source requires `[[[source_id]]]` while listing artifacts uses `[[source_id]]`【/docs/rpc-reference.md†L70-L82】. A minor adjustment to Google’s frontend payload structure—adding or removing a wrapper array—causes immediate `TypeError` exceptions or silent data loss. Without access to Google’s internal schema definitions, developers must rely on brittle manual testing against live traffic.

## Authentication and Security Risks

The authentication model for these internal endpoints introduces **token churn** and **CSRF exposure** that public APIs typically avoid. The client in [`src/notebooklm/auth.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/auth.py) relies on the same session cookies and CSRF tokens used by the web UI rather than OAuth2 access tokens with defined expiration behaviors【/src/notebooklm/auth.py】.

These tokens expire unpredictably, causing `401/403` errors that require manual intervention via `refresh_auth()`. Furthermore, [`src/notebooklm/_core.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/_core.py) constructs the `X-CSRF-Token` header from stored credentials【/src/notebooklm/_core.py†L78-L85】. Any accidental logging of HTTP headers or token leakage creates immediate request forgery vulnerabilities, as these tokens lack the scoped permissions and rotation mechanisms of official API credentials.

## Operational Risks: Rate Limits and Lack of Versioning

Operating against undocumented endpoints means navigating **opaque rate limiting** without the safety rails of official quota management. Google enforces per-user and per-project quotas on the `batchexecute` endpoint, but undocumented calls do not return standard `429` error codes with `Retry-After` headers.

As noted in [`docs/stability.md`](https://github.com/teng-lin/notebooklm-py/blob/main/docs/stability.md), developers must manually implement “delays between bulk operations” to avoid triggering back-off mechanisms【/docs/stability.md†L31-L38】. Without published rate limits, automated retry logic risks compounding the problem through aggressive polling. Additionally, the absence of versioning means no migration path exists when Google deprecates functionality; the [`CLAUDE.md`](https://github.com/teng-lin/notebooklm-py/blob/main/CLAUDE.md) guide explicitly warns that “All RPC method IDs … are undocumented and subject to breakage”【/CLAUDE.md†L18-L22】.

## Mitigation Strategies for Production Use

While the risks are inherent, defensive coding practices can reduce exposure to these undocumented Google RPC API vulnerabilities.

### Implementing Resilient Authentication Handling

Wrap all RPC calls with automatic token refresh logic to handle authentication churn gracefully:

```python
import asyncio
from notebooklm import NotebookLMClient
from notebooklm.rpc.types import RPCMethod
from notebooklm.exceptions import RPCError

async def list_notebooks():
    async with await NotebookLMClient.from_storage() as client:
        # Simple wrapper that retries once on auth error

        try:
            return await client.notebooks.list()
        except RPCError as exc:
            if exc.status_code == 401:          # token expired

                await client.refresh_auth()
                return await client.notebooks.list()
            raise

if __name__ == "__main__":
    print(asyncio.run(list_notebooks()))

```

This pattern catches the most common failure mode—expired tokens—and re-authenticates without crashing the application.

### Detecting Method-ID Breakage

Implement explicit error handling to surface when Google changes RPC method identifiers:

```python
from notebooklm import NotebookLMClient
from notebooklm.rpc.types import RPCMethod
from notebooklm.exceptions import RPCError

async def safe_get_notebook(nb_id: str):
    async with await NotebookLMClient.from_storage() as client:
        try:
            return await client.notebooks.get(nb_id)
        except RPCError as e:
            # 404 can indicate a changed method ID

            if e.status_code == 404:
                raise RuntimeError(
                    f"RPC method {RPCMethod.GET_NOTEBOOK.value} may have changed. "
                    "Refresh the repository or check docs/rpc-reference.md."
                )
            raise

# usage

# asyncio.run(safe_get_notebook("abc123"))

```

This surfaces clear diagnostic information when undocumented endpoints shift, prompting immediate maintenance rather than silent failures.

### Respecting Rate Limits in Bulk Operations

Add deliberate delays and exponential back-off to avoid triggering undocumented quota enforcement:

```python
import asyncio
from notebooklm import NotebookLMClient
from notebooklm.exceptions import RPCError

async def bulk_add_urls(nb_id: str, urls: list[str], delay: float = 1.0):
    async with await NotebookLMClient.from_storage() as client:
        for url in urls:
            try:
                await client.sources.add_url(nb_id, url)
                await asyncio.sleep(delay)   # simple back-off

            except RPCError as e:
                if e.status_code == 429:
                    # exponential back-off on quota hit

                    await asyncio.sleep(delay * 2)
                    await client.sources.add_url(nb_id, url)

# asyncio.run(bulk_add_urls("nb123", ["https://example.com/a", "..."]))

```

This manual rate-limiting compensates for the lack of documented quota headers, reducing the risk of account throttling or suspension.

## Summary

Integrating with undocumented Google RPC APIs, as demonstrated by the **notebooklm-py** client, requires accepting significant operational liabilities:

- **Method-ID volatility** in [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/rpc/types.py) means endpoints can disappear without notice, causing immediate 404 errors across all dependent functions.
- **Parameter-nesting fragility** demands exact array depths (single through quadruple nesting) that break when Google adjusts internal UI payloads.
- **Authentication churn** via session cookies and CSRF tokens in [`src/notebooklm/auth.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/auth.py) creates unpredictable 401/403 failures requiring manual refresh cycles.
- **Opaque rate limiting** without standard retry headers necessitates defensive delays to avoid account throttling or suspension.
- **Zero versioning guarantees** mean no migration paths exist when functionality changes, as warned in [`CLAUDE.md`](https://github.com/teng-lin/notebooklm-py/blob/main/CLAUDE.md) and [`docs/rpc-reference.md`](https://github.com/teng-lin/notebooklm-py/blob/main/docs/rpc-reference.md).

## Frequently Asked Questions

### What makes undocumented Google RPC APIs different from official REST APIs?

Official Google REST APIs provide versioned endpoints, documented schemas, deprecation notices, and standard error codes like `429` for rate limiting. Undocumented RPC APIs, such as those used in `notebooklm-py`, rely on reverse-engineered method IDs stored in [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/rpc/types.py) and lack any stability guarantees, versioning, or migration paths, making them susceptible to sudden breaking changes.

### How can I detect when Google changes an RPC method ID?

Monitor for `404` errors on calls that previously succeeded, as these often indicate the obfuscated method identifier has shifted. Implement explicit error handling that checks `RPCError.status_code` and compares against the current `RPCMethod` enum values from the repository. When a mismatch occurs, raise a diagnostic error prompting users to update [`src/notebooklm/rpc/types.py`](https://github.com/teng-lin/notebooklm-py/blob/main/src/notebooklm/rpc/types.py) from the latest repository version.

### Why do parameter nesting levels matter in batchexecute calls?

The `batchexecute` endpoint expects parameters wrapped in specific array depths—ranging from single brackets `[]` to quadruple brackets `[[[[]]]]`—depending on the operation type. These nesting patterns mirror internal Google UI state rather than logical data structures. If Google adjusts their frontend payload format, hardcoded nesting in methods like `client.sources.add_url()` or `client.notebooks.delete()` will cause `TypeError` exceptions or silent data corruption.

### What are the consequences of hitting rate limits on undocumented endpoints?

Unlike official APIs that return `429` status codes with `Retry-After` headers, undocumented RPC endpoints may throttle requests silently or return generic errors. Repeated polling without exponential back-off can trigger account-level sanctions, including temporary throttling or permanent suspension. The `notebooklm-py` documentation in [`docs/stability.md`](https://github.com/teng-lin/notebooklm-py/blob/main/docs/stability.md) recommends implementing manual delays between bulk operations to mitigate this risk.