Skip to main content
Notte sessions expose a Chrome DevTools Protocol (CDP) endpoint that you can connect to with Playwright. This allows you to use Playwright’s API directly while still benefiting from Notte’s cloud infrastructure, anti-detection features, and session management.

Prerequisites

Install Playwright alongside the Notte SDK:
pip install notte-sdk playwright

Connect Playwright to Notte Session

Get the CDP URL from a Notte session and connect Playwright to it:
from notte_sdk import NotteClient
from playwright.sync_api import sync_playwright

client = NotteClient()

# Start a Notte session
with client.Session() as session:
    # Get CDP WebSocket URL
    cdp_url = session.cdp_url()
    print(f"CDP URL: {cdp_url}")

    # Connect Playwright to the Notte session
    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(cdp_url)

        # Access the page (Notte sessions have one context with one page)
        context = browser.contexts[0]
        page = context.pages[0]

        # Use Playwright API directly
        page.goto("https://example.com")
        print(f"Title: {page.title()}")

        # Take a screenshot
        page.screenshot(path="screenshot.png")
Notte sessions automatically create a browser context with one page. Access it via browser.contexts[0].pages[0].

Use Both Notte and Playwright APIs

You can use both the Notte session API and Playwright simultaneously:
from notte_sdk import NotteClient
from playwright.sync_api import sync_playwright

client = NotteClient()

with client.Session() as session:
    # Use Notte's built-in page
    notte_page = session.page
    notte_page.goto("https://example.com")

    # Also connect Playwright for advanced features
    cdp_url = session.cdp_url()

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(cdp_url)
        playwright_page = browser.contexts[0].pages[0]

        # Use Playwright's advanced features
        playwright_page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())

        # Navigate with route interception active
        playwright_page.goto("https://example.com/gallery")

        # Use Playwright's network monitoring
        with playwright_page.expect_response("**/api/data") as response_info:
            playwright_page.click("button#load-data")
        response = response_info.value
        print(f"API Response: {response.status()}")

Async Playwright Support

Notte works with both sync and async Playwright:
import asyncio
from notte_sdk import NotteClient
from playwright.async_api import async_playwright

async def main():
    client = NotteClient()

    with client.Session() as session:
        cdp_url = session.cdp_url()

        async with async_playwright() as p:
            browser = await p.chromium.connect_over_cdp(cdp_url)
            context = browser.contexts[0]
            page = context.pages[0]

            await page.goto("https://example.com")
            title = await page.title()
            print(f"Title: {title}")

            await page.screenshot(path="screenshot.png")

asyncio.run(main())

Advanced: Multiple Pages and Contexts

Create additional pages or contexts using Playwright:
from notte_sdk import NotteClient
from playwright.sync_api import sync_playwright

client = NotteClient()

with client.Session() as session:
    cdp_url = session.cdp_url()

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(cdp_url)

        # Create a new context with custom settings
        context = browser.new_context(
            viewport={"width": 1920, "height": 1080},
            user_agent="Custom User Agent"
        )

        # Create multiple pages
        page1 = context.new_page()
        page2 = context.new_page()

        page1.goto("https://example.com")
        page2.goto("https://google.com")

        print(f"Page 1: {page1.title()}")
        print(f"Page 2: {page2.title()}")

Network Interception

Use Playwright’s powerful network interception with Notte sessions:
from notte_sdk import NotteClient
from playwright.sync_api import sync_playwright

client = NotteClient()

with client.Session() as session:
    cdp_url = session.cdp_url()

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(cdp_url)
        page = browser.contexts[0].pages[0]

        # Block images and stylesheets for faster loading
        page.route("**/*.{png,jpg,jpeg,css}", lambda route: route.abort())

        # Modify API responses
        def handle_route(route):
            if "api/config" in route.request.url:
                route.fulfill(json={"feature_enabled": True})
            else:
                route.continue_()

        page.route("**/api/**", handle_route)

        page.goto("https://example.com")

Browser Events and Monitoring

Listen to browser events using Playwright:
from notte_sdk import NotteClient
from playwright.sync_api import sync_playwright

client = NotteClient()

with client.Session() as session:
    cdp_url = session.cdp_url()

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(cdp_url)
        page = browser.contexts[0].pages[0]

        # Listen to console messages
        page.on("console", lambda msg: print(f"Console: {msg.text}"))

        # Listen to page errors
        page.on("pageerror", lambda err: print(f"Error: {err}"))

        # Listen to requests
        page.on("request", lambda req: print(f"Request: {req.url}"))

        # Listen to responses
        page.on("response", lambda res: print(f"Response: {res.url} - {res.status}"))

        page.goto("https://example.com")

Best Practices

1. Use Context Managers

Always use context managers for both Notte and Playwright to ensure proper cleanup:
with client.Session() as session:
    with sync_playwright() as p:
        # Your code here
        pass

2. Prefer Notte’s Built-in Page

For simple automation, use session.page directly. Only connect Playwright when you need advanced features like network interception or custom contexts.

3. Session Timeout

Remember that Notte sessions have a timeout. For long-running Playwright operations, increase the timeout:
with client.Session(timeout_minutes=20) as session:
    # Long Playwright automation
    pass

4. Handle CDP Disconnections

CDP connections can be interrupted. Wrap operations in try-except blocks:
try:
    browser = p.chromium.connect_over_cdp(cdp_url)
    # ... operations
except Exception as e:
    print(f"CDP connection failed: {e}")

When to Use Playwright with Notte

Use Playwright directly when you need:
  • Network interception: Block resources, modify requests/responses
  • Advanced event monitoring: Console logs, network events, page errors
  • Multiple contexts: Separate browser contexts with different settings
  • Custom browser settings: Specific viewport, user agent, or permissions per context
  • Playwright’s testing utilities: Screenshots with full-page scrolling, PDF generation, etc.
For most automation tasks, session.page (which is already Playwright-compatible) is sufficient.

Next Steps