> ## Documentation Index
> Fetch the complete documentation index at: https://notte-experiment-visibility-md-links.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Playwright vs Notte Controls

> Understanding the difference between direct Playwright control and Notte's AI-enabled SDK

When working with Notte sessions, you have two ways to interact with the browser: using Playwright directly via CDP, or using Notte's AI-enabled SDK methods. Both approaches work with the same session, and you can even mix them in your automation.

## Direct Playwright Control

When you access `session.page`, you get a Playwright-compatible page object that connects directly to the browser via Chrome DevTools Protocol:

{/* @sniptest testers/sessions/playwright-vs-notte/playwright_direct.py */}

```python playwright_direct.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    page = session.page
    page.goto("https://example.com")
    page.fill("input[name='email']", "user@example.com")
    page.click("button[type='submit']")
```

This gives you the full Playwright API - everything you can do with Playwright works here. You control the browser directly through WebSocket connections with low latency.

## Notte SDK Methods

Notte provides high-level methods designed for AI agents and structured automation:

{/* @sniptest testers/sessions/playwright-vs-notte/notte_sdk_methods.py */}

```python notte_sdk_methods.py theme={null}
from notte_sdk import NotteClient

client = NotteClient()

with client.Session() as session:
    session.execute(type="goto", url="https://example.com")
    actions = session.observe(instructions="Fill the email input")
    session.execute(actions[0])  # Execute the action the AI recommends
    data = session.scrape(instructions="Extract all product names")
```

These methods use Notte's backend to execute actions, with built-in AI capabilities, observability, and error handling.

## Key Differences

| Feature                | Playwright (`session.page`)   | Notte SDK (`execute/observe/scrape`)          |
| ---------------------- | ----------------------------- | --------------------------------------------- |
| **API Surface**        | Full Playwright API           | Streamlined action-based API                  |
| **Dependencies**       | Requires `playwright` package | Just `notte-sdk`                              |
| **Element Selection**  | Manual CSS/XPath selectors    | AI-powered natural language + selectors       |
| **Page Understanding** | Manual interpretation         | AI describes page with `observe()`            |
| **Data Extraction**    | Manual parsing                | Structured LLM-powered `scrape()`             |
| **Observability**      | Manual logging                | Session replay, action recording, live viewer |
| **Error Handling**     | Manual try/except             | Automatic retries and validation              |
| **Network Control**    | ✅ Intercept, modify requests  | ❌ Not available                               |
| **Latency**            | Lower (WebSocket)             | Higher (HTTP API)                             |
| **Action Coverage**    | Everything                    | Everything via extensive action library       |

## Why Use Playwright?

Choose `session.page` when you need:

* **Network control** - Intercept, block, or modify requests and responses
* **Event monitoring** - Listen to console logs, network events, page errors
* **Lowest latency** - Direct WebSocket communication for high-speed operations
* **Standard patterns** - Use familiar Playwright code and examples
* **Fine-grained control** - Access to every Playwright feature

<CodeGroup>
  ```python Python theme={null}
  from notte_sdk import NotteClient
  from playwright.sync_api import sync_playwright

  client = NotteClient()

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

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

      # Listen to network requests
      page.on("request", lambda req: print(f"→ {req.url}"))
      page.on("response", lambda res: print(f"← {res.url} ({res.status})"))

      page.goto("https://example.com")
  ```
</CodeGroup>

## Why Use Notte SDK?

Choose `session.execute()`, `observe()`, and `scrape()` when you need:

* **AI-powered automation** - Let AI find elements and understand pages
* **Structured data extraction** - Extract data into Pydantic models automatically
* **Built-in observability** - Session replays, trajectory tracking, live viewer
* **Simpler API** - Smaller learning curve, no Playwright knowledge required
* **Production reliability** - Automatic retries, error handling, validation
* **Agent workflows** - Designed for AI agents with semantic action spaces

<CodeGroup>
  ```python Python theme={null}
  from notte_sdk import NotteClient
  from pydantic import BaseModel

  client = NotteClient()

  class Product(BaseModel):
      name: str
      price: float

  with client.Session() as session:
      session.execute(type="goto", url="https://example.com/products")

      # AI understands the page
      obs = session.observe(instructions="Find the search box")
      action = obs.space.first()  # AI picks the right element
      session.execute(action.with_value("laptops"))

      # Structured extraction with LLM
      products = session.scrape(
          response_format=list[Product],
          instructions="Extract all products with names and prices"
      )

      # Every action is recorded
      replay = session.replay()
      replay.download("automation.mp4")
  ```
</CodeGroup>

## Mix Both Approaches

You can combine both methods in the same session:

<CodeGroup>
  ```python Python theme={null}
  from notte_sdk import NotteClient

  client = NotteClient()

  with client.Session() as session:
      # Use Notte for high-level navigation
      session.execute(type="goto", url="https://example.com")

      # Switch to Playwright for network control
      page = session.page
      page.route("**/api/*", lambda route: route.continue_(headers={
          **route.request.headers,
          "Authorization": f"Bearer {token}"
      }))

      # Back to Notte for AI-powered scraping
      data = session.scrape(instructions="Extract all article titles")
  ```
</CodeGroup>

## When to Choose What

### Use Playwright if:

* You need network interception or request modification
* You're integrating existing Playwright scripts
* Performance is critical (milliseconds matter)
* You need to listen to browser events

### Use Notte SDK if:

* Building AI agents that understand web pages
* You want structured data extraction
* You need session replay and debugging features
* You prefer simpler, action-based API
* Building production systems with error handling

### Use Both if:

* You need network control AND AI features
* Complex workflows with different requirements
* You want the flexibility of both approaches

## Next Steps

<CardGroup cols={2}>
  <Card title="Connect with Playwright" icon="p" href="/features/sessions/playwright.md">
    Learn how to use Playwright with Notte sessions
  </Card>

  <Card title="Session Configuration" icon="gear" href="/features/sessions/configuration.md">
    Configure sessions with advanced options
  </Card>

  <Card title="Actions Reference" icon="hand-pointer" href="/sdk-reference/misc/gotoaction.md">
    Explore all available Notte actions
  </Card>

  <Card title="Recordings" icon="video" href="/features/sessions/recordings.md">
    Debug with session replays
  </Card>
</CardGroup>
